Photoruction工事中!

Photoructionの開発ブログです!

WEBワーカーを外部ファイルを使わずにインラインで実行し方

こんにちは。Webチームのジョンです。

今回はWEBワーカーについて、記事を書きました。

WEBワーカーとは

WEBワーカーは独立しているJavascriptでバックグラウンドに走るスクリプトになります。一般的にはJavascriptはシングルスレッドプログラミング言語のため同時に複数スクリプトを走らせることができません。でもWEBワーカーを使うことでJavascriptのメインプロセスをブロックすることなしで複数のスクリプトを実行することができます。

WEBワーカーの基本的な使い方

demo_workers.js

var i = 0;

function timedCount() {
  i = i + 1;
  postMessage(i);
  setTimeout("timedCount()",500);
}

timedCount();

main_script.js

if (typeof(w) == "undefined") {
  w = new Worker("demo_workers.js");
}

w.onmessage = function(event){
  console.log(event.data);
};
  1. まず、WEBワーカーに実行したいスクリプトを作り、demo_worker.jsファイルに保存しました。
  2. メインのスクリプトnew Worker()でWEBワーカーのインスタンスを作り、WEBワーカーに実行したいスクリプトのファイルを第一引数に設定する。
  3. WEBワーカーのインスタンスonmessageイベントを付けてWEBワーカーから送られたメッセージをメインスクリプトに受け取りconsole.logで出す。

外部ファイルを使わずに

  1. まずWEBワーカーに実行したいスクリプトを文字列として変数に格納する。
  2. encodeURIComponentファンクションを使い、スクリプトの文字列のデータURIを作成します

     const workerCode = `
         var i = 0;
    
         function timedCount() {
             i = i + 1;
             postMessage(i);
             setTimeout("timedCount()",500);
         }
    
         timedCount();
     `;
     const workerURI = `data:text/javascript;charset=utf-8,${encodeURIComponent(workerCode)}`;
    
  3. blobを使うこともできます

     const workerBlob = new Blob([workerCode], { type: 'text/javascript' });
     const workerURL = URL.createObjectURL(workerBlob);
    
  4. 後は、基本の使い方と全く同じになります。

     // encodeURIComponentを使った場合
     const w = new Worker(workerURI);
    
     // blobを使った場合
     // const worker = new Worker(workerURL);
    
     w.postMessage('Hello, worker!');
     w.onmessage = function(event){
       console.log(event.data);
     };
    

まとめ

インラインでWEBワーカーのコードを書くのは便利ですがデメリットとメリットがあります。スクリプトを文字列にしないといけないため、管理しにくくなりますし、IDEのコードハイライトや文法チェック、リント等が効かなくなります。その時は別のJavascriptファイルに入れた方がいいと思います。

小さいコードであればインラインで書いても問題ないですが、そもそもWEBワーカーを使うべきなのか?という問題も出てきます。

いろいろWEBワーカーの書き方がありますが、結局自分のユースケースによってどれを一番ふさわしいのかを自分で判断しないといけないです。

PhotoructionはPHPerKaigi 2023ダイアモンドスポンサーとして協賛・登壇いたします!

こんにちは。Webエンジニアの下川原です。

いつもはPhotoructionの開発ブログとして、記事をアップしていますが、今回は告知させてください!

弊社は、PHPerKaigi 2023のダイアモンドスポンサーとして協賛させていただいています。

PHPerKaigi 2023の詳細はこちら

開催日:2023年3月23日(木)〜 3月25日(土)

場所 :練馬区立区民・産業プラザ Coconeriホール およびニコニコ生放送

対象 :PHPエンジニアおよびWeb技術のエンジニア

当日はピッチイベントが開催されます。今回は弊社社員が登壇します!

「#建設の世界を限りなくスマートにする」

というミッションのもと建設支援クラウドPhotoructionを提供して早5年が過ぎました。

サービスの基盤の大部分はPHP/Laravelで実現されております。

我々が提供するサービスがどのような課題を解決しているか、どのような構成で実現されているか

日々技術的な課題に向き合い改善しているかを紹介します!

ピッチ日程

建設DXの世界を知っていただくために、鋭意準備を進めております!

気になる方は是非是非、ご聴講ください!(チケットまだ買えるはずです)

CRE勉強会始めました。

CREチームの桑畑です。

チーム内で実施している、CRE勉強会について紹介します。

目的・背景

  • チームのスキルの底上げをする
  • タスクを個別具象で終わらせることなく、抽象的な理解・知見を養う。(あらゆるタスクからでも学びの機会を得る。)
  • 調べたことをアウトプットする機会を強制的に作ることで学びの効果を向上させる
  • 他チームへの知財共有にもなれば尚良し

運用方法

  • 実施サイクル:隔週
  • テーマ選定:
    • 業務内のタスクで解消しきれていない疑問
    • CRE業務を効率化するための共有知
    • 既存システムの実装・処理フローでの疑問点
    • 理解を深めたいテーマなんでも
  • 当日
    • テーマに対して調査したことの共有
    • ディスカッション
    • 次のテーマ選定

CRE勉強会実施例

  1. テストコード
    1. フォトラクションでは、テストコードの記述が必須。Unitテスト、Featureテストに対して、データプロバイダ、Mock、コマンド実行時のテストの記述方法など。各自実装したテストコードやレビュー済みコードなどを参考にして、振り返りを実施した。
  2. フォトラクションのインフラシステム設計・処理深堀り
    1. フォトラクションで利用されているインフラサービスに対して、処理・設計などで理解が曖昧になっている部分の深堀りを実施した。
  3. サービスコンテナ・サービスプロバイダについて
    1. Laravelのサービスコンテナ・サービスプロバイダについて、事前に理解を深めた後に、実装で利用されている部分からピックアップして、サービスコンテナ・サービスプロバイダの動きを確認した。
  4. 不具合発生時の対応フロー
    1. 不具合発生時の対応フローを言語化した。不具合テーマに応じて、対応フローを明確にしていく動きへ繋がった。

最後に

業務内でのタスクのみだと、細切れになってる場合も多く、個別の問題解決に帰着してしまう場合があります。個別の事象から抽象度を上げることで、他の事象にも活かせられるような理解、知識を身に着けていくことを意識出来たらと思います。

勉強会で共有した内容が、CREの業務内でも活かされる機会も生まれており、好循環のサイクルを回ることを期待しています。好奇心を持って、日々の業務に取り組むことで、日進月歩していきたいと思います。

株式会社フォトラクションでは一緒に働く仲間を募集しています

不具合調査手順をまとめてみた!

こんにちは。CREエンジニアの田中です。日々不具合の調査や対応をしています。

今回は、日頃行っている不具合調査の手順をまとめてみたいと思います!

ひとえに不具合といっても、色々なパターンがあるので、今回の記事では、「Webアプリケーションの不具合」の場合をイメージしてまとめてみます。

調査手順


  1. CS(カスタマーサポート)から、不具合のお問い合わせの連絡をいただく
    1. 問い合わせ内容の確認
    2. 調査に必要な情報をヒアリング
      1. CSからお客様に質問してもらう
    3. 不具合検知のツールでエラーログが吐かれているか確認
      1. bugsnagを利用しています(Datadogに移行予定)
  2. 再現確認
    1. 再現手順がわかっている場合
      1. 自分の環境でも再現できるかの確認
      2. ブラウザのdevtool>networkタブで問題となる処理を確認する    
        1. 1-cで把握できている場合もある
    2. 再現手順がわかっていない場合
      1. きつい。。この場合、自分であれこれ確認しにいきます
      2. それでも、再現手順が分からない=CSの方やテスターの方が確認して分からないということ
        1. エンジニア視点で、不具合の絞り込みをする ⇒ 3へ進む
  3. ソースコードを確認
    1. エディタの検索ツールで、エンドポイント or 関数名を検索  
      1. 上流のControllerから問題となる処理箇所まで追っていく
    2. デバッグをする
      1. デバッグプラグイン(Xdebugなど)を入れていれば、ツールのブレイクポイント置いて、デバッグ
      2. 各言語やフレームワークデバッグ方法でデバッグする
        1. 弊社はLaravelを用いているので、loggerヘルパーだったり、Facadesのクラスを利用してログを出力しています
    3. 問題を切り分ける
      1. 自社のソースコード or 連携している外部サービス が問題かを切り分ける
        1. 自社のソースコードの場合、デバッグをしていけば、原因は突き止められる(はず)
          1. 勿論、ネットワークやインフラなど、ソースコードのレベルではない場合はあるので、問題が何なのかを切り分ける
        2. 連携している外部サービスの場合
          1. 社内の詳しい人とコミュニケーションを取る or 外部サービスの窓口の方に質問する
  4. 原因を特定
    1. 3の作業を進めていくと、不具合の詳細や原因が突き止められる
      1. 原因が突き止められなかったにせよ、少なくとも、最初のお問合せ時点での不具合内容(実際の不具合状況とは異なる場合が割とある)よりは、詳細になっている
    2. 調査内容を情報を起票されたチケットやスレッドに記載していく
      1. 現在CREチームでは、調査の効率化目的で、対応した不具合に対して、メモを残すようにしている(Notion)
      2. 対応後、メモ→ドキュメントにしていくことで、対応の可視化をし、フローの洗練を行なっている
  5. CSや関係者に進捗や原因を報告
  6. エンジニアに依頼 or 自分で対応
    1. 依頼する際は、調査結果、該当部分のGithubリンクと不具合のチケットリンクをまとめて送っている
      1. 依頼先のエンジニアがスムーズに不具合内容の把握改修作業に取り組めるように、なるべく簡潔かつMECEになるよう心がけている(ただ、いつも長くなってしまう、、)

まとめ


不具合の原因調査はい不確実性を少しずつ、クリアにしていっております。

もっといいやり方は全然あると思いますので、今回手順を可視化し、洗練していこうと思います!

参考になれば幸いです。

株式会社フォトラクションでは一緒に働く仲間を募集しています

建設テックのエンジニアって特別な何かがあるの?

建設テックのエンジニアって特別な何かがあるの?

はじめましての人ははじめまして Androidエンジニアの久木田です。

今回は建設テックで施工管理サービスを提供しているエンジニアって他のIT企業とどれだけ違うのかについての記事です。 (ちなみに、多分他の会社でも当てはまるだろうと思って書いていますが、Photoructionでの経験を元にしています)

TL;DR

めちゃくちゃ特別なことはなく、建設業界の知識や業務理解は当然必要ですが、toB SaaSの企業って多分大体こんなもんだよねって感じです。

特別なこと

どんな特別なことがあるんだろうと思って記事を開いた人が多いんじゃないかと思うので、最初に特別なことについてまとめておきます。

  1. PDFをよく扱う
  2. オフラインでも業務アプリとして問題なく機能する必要がある
  3. 写真の中に黒板をオーバーレイする

PDFをよく扱う

図面などを扱う機会が多いためなのと、日報などの報告書がPDFで出力されるためです。 どうしても外部ライブラリに頼ることになるので辛みが出てくる場面ではあります。

オフラインでも業務アプリとして問題なく機能する必要がある

他にはあまりそういうアプリってないなと思っています。(オンラインである必要のないアプリというのはありますが) そもそもどうしてオフラインでの動作が必要かというと、わかりやすいのが山中での土木工事だとモバイルネットワークの圏外なことは想像に難くないと思います。 また、高層ビルの建設時などはモバイルネットワークのアンテナよりも上に行くと電波が入らなくなっていきます。 そういった場面でも問題なく動作可能であることが重要であるため、建設テックのアプリではオフラインで動作するようになっています。

写真の中に黒板をオーバーレイする

写真内に情報が表示できないといけないことが多くあるので、写真の一部に電子小黒板というものを表示できるようになっています。 カメラを使うアプリは色々ありますが、オーバーレイの機能があるのはリッチなカメラアプリくらいかなと思うので珍しい機能かなと思います。

正直、これくらいですかね、、、

toCtoB SaaSの違い

建設テックで特別なことはそれくらいなんですが、そもそもtoB SaaSと、toCサービスを開発するのに大きな違いがあります。 ただし、弊社がVerticalなtoBなのでHorizontalな企業とは違いがある可能性があります。

  1. 提供先の業務知識が必要
  2. ドッグフーディングできない

提供先の業務知識が必要

これは言わずもがなだとは思いますが、知識量や解像度が高くないとこの機能だれがいつ使うんだという想像すらできないし、企画時により良い提案もできないのでとにかくここは豊富であるに越したことないです。 (僕は入社後にドメイン出身者が家を建てる一通りの工程を解説してもらったりしました)

ドッグフーディングできない

他の産業向けのサービスなので、普段使うことは絶対にないし、業務で使うにも想定されてる使い方とは違うので改善点の洗い出しがあまりできません。 なので、ユーザーインタビューがとても重要です。また、ドメイン出身者のいわゆるドメインエキスパートの存在は重要です。

他のWeb企業と変わらないこと

色々違いを書きましたが、多くは普通のWeb企業と変わらないです。 使用技術もAWSPHP、アプリはネイティブで作成されています。開発フローもスクラムですし、GitHubやSlackも使ってます。

まとめ

特に大事なのはやっぱり業界理解なのかなと思っています。 ここをおろそかにするといい製品を作れないし、使われていてもなんで使われるのかとかもよくわからないままなのかなと思います。 また、今回は 建設テックでの記事ですが、他の業界やHorizontal SaaSの企業だとどうなのかとかも気になりますね!

株式会社フォトラクションでは一緒に働く仲間を募集しています

リリースノートの作成で楽をする

はじめに

こんにちは、Photoructionでモバイルチームのテックリードをしている數田です。

Photoruction Advent Calendar 2022の25日目の記事になります。

現在フォトラクションのモバイルアプリは基本的に毎週水曜日にリリースしています、リリース回数を増やすと、手動でリリースノートを作成していると漏れが発生する可能性が高くなります。

リリースノートを自動で作成する手段を検討すると、GitHubAutomatically generated release notesが追加されたので利用するようにしました。

GitHub ReleaseページでGenerate releasenotesを実行すると以下のようになります。

## What's Changed
* [JIRA-1] 新機能1 by {GitHub User} in {Github repo}/pull/101
* [JIRA-2] 新機能2 by {GitHub User} in {Github repo}/pull/102
* [JIRA-3] バグ改修1 by {GitHub User} in {Github repo}/pull/103

## New Contributors
* {GitHub User} made their first contribution in {Github repo}/pull/1

**Full Changelog**: {GitHub repo}/commits/1.0.1

What's ChangedにマージされたPRが全て出るので、変更の内容を分類したくなります。

**Automatically generated release notes ではPull Requestにラベルをつけると分類できるようになります。

Pull Requestに自動でラベルをつける方法

リリースノートに機能追加、バグ改修、リファクタリングが分類して書いてあると影響範囲がわかりやすそうです。

Pull Requestに手動でラベルを付与する運用にすると漏れが発生するので、自動で付与する方法を考えます。

GitHub Actionsの PR Labeler を利用するとブランチ名を元にPRのラベルを自動で付与することができます。ブランチのプレフィックスにそれぞれがわかるように設定します。

Feature: ['feature/*']
bug: ['bugs/*']
refactor: ['refactor/*']

課題管理システム

リリースノートから課題管理のチケットにリンクが貼られていると便利ですがGithubのIssues以外のJIRAなどを利用していると、リリースノートからに課題のURLを書くのも面倒です。GitHubAutolink referencesでJIRAなどの設定をすることによって、JIRA-1と書くだけでPull RequestやIssueなどでリンクが自動で設定されます。

リリースノートの設定

リリースノートでPull Requestを分類する設定をを.github/release.ymlに追加します。

changelog:
  categories:
    - title: 新機能 
      labels:
        - Feature
    - title: 不具合修正
      labels:
        - bug
    - title: リファクタリング
      labels:
        - refactor
    - title: Other Changes
      labels:
        - "*"

GitHub ReleaseページでGenerate releasenotesを実行すると以下のようになります。

株式会社フォトラクションでは一緒に働く仲間を募集しています

Pathlibでディレクトリ・ファイルを操作する

はじめに

こんにちは、株式会社フォトラクションでPMをしている峠です。

業務でディレクトリやファイル操作でパスを扱うことが多く、これらを Pathlib と呼ばれるPythonのライブラリを用いて操作しています。

今回はPathlibでできる操作をいくつか紹介したいと思います。

Pythonではパス操作時にos などのライブラリを使うことが一般的なイメージがありますが、弊社ではPathlibを使用しています。(参考:pathlibドキュメント

1. 基本パス操作

from pathlib import Path

# Pathインスタンスを作成
path = Path()

"""カレントパスを取得"""
current_path = path.cwd()
print(current_path) => "/content"

"""パスの連結"""
# ①「/」で連結
dir1_path = current_path / 'dir1'
file1_path = dir1_path / 'file1.txt'
print(dir1_path) => "/content/dir1"
print(file1_path) => "/content/dir1/file1.txt"
# ②「joinpath()」で連結
dir2_path = current_path.joinpath('dir2')
file2_path = dir2_path.joinpath('file2.txt')
print(dir2_path) => "/content/dir2"
print(file2_path) => "/content/dir2/file2.txt"

"""ディレクトリの判定"""
dir1_is_dir = dir1_path.is_dir()
file1_is_dir = file1_path.is_dir()
print(dir1_is_dir) => "True"
print(file1_is_dir) => "False"

"""ファイルの判定"""
dir1_is_file = dir1_path.is_file()
file1_is_file = file1_path.is_file()
print(dir1_is_file) => "False"
print(file1_is_file) => "True"

"""ディレクトリの作成"""
# parents=True:中間ディレクトリも含めて作成する
# exist_ok=True:既存のディレクトリが指定されていてもエラーを出力しない
dir1_path.mkdir(exist_ok=True,parents=True)

"""ファイルの作成"""
# exist_ok=True:既存のディレクトリが指定されていてもエラーを出力しない
file1_path.touch(exist_ok=True)

"""パスの存在を確認"""
dir1_exist = dir1_path.exists()
file1_exist = file1_path.exists()
print(dir1_exist) => "True"
print(file1_exist) => "True"
dir2_exist = dir2_path.exists()
file2_exist = file2_path.exists()
print(dir2_exist) => "False"
print(file2_exist) => "False"

2. ディレクトリ・ファイルの操作

"""ディレクトリ・ファイルの名前を取得"""
dir1_name = dir1_path.name
file1_name = file1_path.name
print(dir1_name) => "dir1"
print(file1_name) => "file1.txt"

"""ディレクトリ・ファイルの拡張子を除いた名前を取得"""
dir1_stem = dir1_path.stem
file1_stem = file1_path.stem
print(dir1_stem) => "dir1"
print(file1_stem) => "file1"

"""ディレクトリ・ファイルの拡張子を取得(なければ取得しない)"""
dir1_suffix = dir1_path.suffix
file1_suffix = file1_path.suffix
print(dir1_suffix) => ""
print(file1_suffix) => ".txt"

"""パスを文字列としてを取得"""
dir1_str = str(dir1_path)
file1_str = str(file1_path)
print(dir1_str) => "/content/dir1"
print(file1_str) => "/content/dir1/file1.txt"

3. ディレクトリ・ファイル一覧の取得

# dir1に追加でディレクトリ・ファイルを作成
dir1_path.joinpath('file2.txt').touch(exist_ok=True)
dir1_path.joinpath('dir1-1').mkdir(exist_ok=True)
dir1_path.joinpath('dir1-2').mkdir(exist_ok=True)

"""ディレクトリ・ファイルの一覧をリストで取得"""
path_list = [path for path in dir1_path.iterdir()]
print(path_list) => "[PosixPath('/content/dir1/file2.txt'),"
                                            "PosixPath('/content/dir1/dir1-2'), "
                                            "PosixPath('/content/dir1/file1.txt')," 
                                            "PosixPath('/content/dir1/dir1-1')]"

"""ディレクトリの一覧をリストで取得"""
dir_list = [path for path in dir1_path.iterdir() if path.is_dir()]
print(dir_list) => "[PosixPath('/content/dir1/dir1-2'),"
                                        "PosixPath('/content/dir1/dir1-1')]"

"""ファイルの一覧をリストで取得"""
file_list = [path for path in dir1_path.iterdir() if path.is_file()]
print(file_list) => "[PosixPath('/content/dir1/file2.txt'),"
                                        " PosixPath('/content/dir1/file1.txt')]"

最後に

Pathlibはファイル操作機能が豊富で使い方も感覚的なのでとても便利です。

よかったら使ってみてください。

参考

pathlib - Object-oriented filesystem paths

株式会社フォトラクションでは一緒に働く仲間を募集しています