Photoruction工事中!

Photoructionの開発ブログです!

入社約半年経った所感・感じた課題と今後の展望

はじめまして、モバイルチームでAndroidエンジニアを担当している藤井です。 チームではエンジニアリングマネージャー(以下、EM)という役割を任されていて、大阪に住んでフルリモートで勤務しています。

フォトラクションに入社するまでは、他業界のスタートアップやソーシャルゲームの業界などでWeb開発やモバイル開発を経験してきました。

趣味は格闘技観戦とブラジリアン柔術です。

今回は入社して半年が経った振り返りを兼ねて、私が感じたことや学んだことを共有したいと思います。

入社後に感じたこと


あくまでもモバイルチームに属しているAndroidエンジニアとしての目線ですが、入社後に感じたことは良いと思った点・改善したい点共にいくつかあります。

ただ、改善したい点があるとは言っても決してネガティブな事ではなく、今後の伸び代だと個人的には捉えています。

良いと思った点

  • 週に1回リリースを行い、短いスパンで価値を提供。また、それを実現するためにCI/CDによるデリバリーサイクルの自動化がなされている
  • まだ途上とはいえ大枠の設計方針が確立されており、新規に機能追加する際は比較的迷いが少ない

改善したい点

  • DBアクセスのロジックがUI層から切り離し切れてないなど、設計方針の反映はまだ途上
  • iOS版と比較して、Android版はアプリの利用状況の可視化が出来ているとは言えない
  • アプリが安定性やパフォーマンスに改善の余地がある
  • スクラムの手法についてある程度確立されてはいるものの、まだ手探り且つ見えていないであろう課題もあるので継続的に学んでいく必要がある

EMとして働く上で直面した課題


個人レベルの課題

今までのキャリアではEMの役割を経験したことがなく、イメージできていないことも多かったので不安を感じていました。その不安に対処するため、別チームのEMと定期的に話す機会を設けて情報交換や悩みの相談などを行いました。

また、オンラインでのコミュニケーションがメインのため、部署・チームを越えたコミュニケーションの機会が普段の業務では多いとは言えないなと感じています。 そのため、個人の取り組みとして例えば有志で開催されている輪読会に参加するなど、時間の許す限りチームを越えたコミュニケーションの機会を増やすように努めています。

プロダクトの課題

モバイルアプリの将来像をどうするかという大きな課題が有ったため、PM(プロダクトマネージャー)やTL(テックリード)と共に週一のモバイルリーダー定例を発足し、方針を議論し合うことで対処しました。この課題はアプリの利用状況を可視化して現状を知るところから初めて、徐々に理想の形に持っていけたらと思います。

チームの課題

入社後に感じたことでも言及していましたが、開発方法にスクラムを導入しては居るものの、私自身含めスクラムの経験値が高いとは言えないため、まだまだ手探りで進めている状況が散見されるかなと思っています。そのため、スクラムアジャイルの知識を深める取り組みが必要になってくるのかなと感じています。

また、モバイルアプリのエンジニアがまだまだ少ない状況であるため、採用活動に注力していく必要があります。そのために私自身が会社の事をよく知り会社のことを説明できるようになっておくことや、新たなエンジニアをサポートしていく仕組みの構築が重要だと思っています。

今後の目標や展望


今後はモバイルアプリを改善する足がかりとしてアプリの利用状況を可視化していくことに注力しつつ、プロダクトの課題に向き合っていけたらと考えています。

当然ながら採用活動や開発サイクルの改善などを始めとするチームの課題にも向き合って行きつつ、見えていない課題もまだまだあると思うので、それらを明確にしつつ改善していけたらなと思っています。

また、手探りながらも同じ様にプロダクトやチームの課題に向き合うことを楽しめるエンジニアを募集しているので、少しでも興味を持っていただけたら連絡いただけると嬉しいです。

最後に


余談ですが、この記事はChat-GPTの助けを借りて作成しました。

会社でもGithub Cpilotを試していこうという動きも有り、私自身もこれらのAIプロダクトを公私共にうまく使っていけたらなと考えております。

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

PymupdfでPDFからテキスト情報を取り出す方法

はじめに

初めまして、エンジニアとして株式会社Photoructionでアルバイト中の伊藤純平です!

最近は春のじめっとした暑さにやられて、脱いだら寒い、着たら暑いというジレンマに陥っています。あまりにも気温差が激しいので、服装選びが毎朝のハードルになってしまっていますね。

今回の記事では、PDFからテキスト情報を抽出する方法について説明します。

自分のチームではPDFを扱うことが多く、これらをPyMuPDFと呼ばれるPythonのライブラリを用いて操作しています。

自分が詰まったテキストの位置、色など全テキスト情報の取得について、自分の学びも含めてお伝えできたらなと思います!

PyMuPDFの読み込みや線の取得などについては、過去の記事をぜひ参考にしてください!

導入

PythonでPDFを操作するためのライブラリにもいくつかあり、今回はPymupdfを使っていきます!

まずはPyMuPDFをインストールし、使うためにfitzをインポートします。

pip install PyMuPDF
import fitz

PDFの読み込み

今回の記事はベクター形式のPDFに対応してます!

ベクター形式とはなんぞやという方はこちらを参照してみてください。

# PDFファイルパスの読み込み
pdf_path = input()

# 1ページ目の要素を取得
document = fitz.open(pdf_path)
page = document[0]

print(page.get_text("dict"))

とすると詳細な文字情報が辞書形式で出力されます!

以下はその一例です。

//各ブロックのバウンディングボックス
{'blocks': [{'bbox': (319.2799987792969,582.891845703125,344.1431884765625,588.4169921875), 
 'lines': [{'bbox': (319.2799987792969,582.891845703125,344.1431884765625,588.4169921875), //各行のバウンディングボックス
        'dir': (1.0, 0.0), //行の方向
        'spans': [{'ascender': 0.339375, //文節のリスト
                          'bbox': (319.2799987792969,582.891845703125,344.1431884765625,588.4169921875), //文節のバウンディングボックス
                         'color': 0, //文節の色
                         'descender': 1.140625, //文節の高さ
                         'flags': 8, //文節の文字数
                         'font': 'MS-Gothic', //文節のフォント
                         'origin': (319.2799987792969,587.6400146484375), //文節の原点
                         'size': 5.52515983581543, //文節のサイズ
                         'text': 'Hello_world'}], //文節の文字
                         'wmode': 0}],
         'number': 0,
         'type': 0},
.....}

上のようにテキスト情報以外にもフォントや位置、色、サイズなど情報を取得することができます!

そのほかの方法

PDFファイルから形を保持したままTextにしたいという方は、こちらも便利かもしれません。

import sys
from fitz.**main** import main as fitz_command

# PDFファイルパスの読み込み
pdf_path = input()

cmd = f"gettext  {pdf_path}".split()
saved_parms = sys.argv[1:]
sys.argv[1:] = cmd
fitz_command()
sys.argv[1:] = saved_parms

これを実行することで左下のようなpdfファイルから右下のようにテキストファイルへとテキストを抽出することもできます。

終わりに

いかがでしたでしょうか。

以上が、PDFから文字のすべての情報を取り出す方法についての解説でした。

PDFを扱う際には、PyMuPDFはとても便利なツールです。今回紹介した文字取り出し以外にも描画情報や画像情報を取り出したりすることもできます。

PythonでPDFを扱う際には、ぜひPyMuPDFを試してみてください!

参考

Introduction - PyMuPDF 1.21.0 documentation

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

Python開発で重宝するライブラリpathlibの使い方

はじめに

こんにちは、AIエンジニアの志賀です。

最近は花粉症に悩まされる日々も終わりが差し掛かり、サクラ咲く季節がやって参りました。寒さと花粉を乗り越えた先にある心地の良い期間だと毎年感じさせられます。

このたびはPython開発で重宝するライブラリpathlibの使い方についての技術ブログをご覧いただきありがとうございます。

Python開発において、OSのファイルパスを扱う必要がある場面は多々ありますが、pathlibを使えばOSのファイルパスを簡単に取り扱うことができます。

本記事では、pathlibの基本的な使い方について解説していきますので、Python開発におけるファイルパスの操作について興味のある方は是非最後までご覧ください。

導入

pathlibとは

Pythonには、OSのファイルパスを扱うための標準ライブラリであるos.pathがあります。

しかし、os.pathは文字列操作が必要であったり、パスの区切り文字がOSによって異なるため、パスの扱いに手間がかかることがあります。

こうした問題を解決するために、Python 3.4からはpathlibというライブラリが標準で提供されるようになりました。pathlibは、OSのファイルパスをオブジェクト指向で扱うことができるため、パスの操作が簡単になります。

pathlibの基本的な使い方

まずは、pathlibの基本的な使い方を見ていきましょう。

以下、使用例になります。

from pathlib import Path

# ファイルパスの生成
file_path = Path("path/to/file.txt")

# ディレクトリパスの生成
dir_path = Path("path/to/directory/")

# パスの結合
new_path = dir_path / "new_file.txt"

Pathオブジェクトを生成するには、文字列でパスを指定します。

Windowsの場合は、区切り文字にバックスラッシュを使う必要がありますが、Pathオブジェクトを使えば自動的にスラッシュ(/)に変換されます。

また、パスの結合は「/」演算子で行うことができます。

# ファイルの存在確認
if file_path.exists():
    print("File exists")

# ファイルの読み込み
with file_path.open() as f:
    content = f.read()

ファイルの存在確認にはexistsメソッドを、ファイルの読み込みにはopenメソッドを使います。

ファイル操作が完了した後には必ずclose()メソッドを呼び出す必要があります。

ただし、with文でブロックを作ることで、close()メソッドの呼び出しを自動的に行うことができるため、open()メソッドの呼び出し時にwith文を使用することが推奨されています。

with文を使用する事で、ファイルのクローズ漏れを防止し、コードをより簡潔に保つことができます。

# ファイルの書き込み
with new_path.open(mode="w") as f:
    f.write("Hello, world!")

ファイルに書き込むには、openメソッドのmode引数に"w"を指定します。書き込みが終わったら、closeする必要がないことに注意しましょう。

# ディレクトリの作成
new_dir = Path("new_directory/")
new_dir.mkdir()

ディレクトリを作成するには、mkdirメソッドを使います。

# ディレクトリ内のファイル一覧の取得
for file_path in new_dir.glob("*"):
    print(file_path)

# パスの情報取得
print(file_path.name)  # ファイル名を取得
print(file_path.suffix)  # 拡張子を取得
print(file_path.parent)  # 親ディレクトリを取得
print(file_path.is_file())  # ファイルかどうか判定

globメソッドを使えば、ディレクトリ内のファイル一覧を取得することができます。

また、Pathオブジェクトには、ファイル名、拡張子、親ディレクトリを取得するメソッドが用意されています。

is_fileメソッドで、Pathオブジェクトがファイルかどうかを判定することもできます。

終わりに

以上が、Python開発で重宝するライブラリであるpathlibの基本的な使い方についての解説でした。

いかがでしたでしょうか。

pathlibを使えば、OSのファイルパスをオブジェクト指向で扱えるため、ファイルパスの操作が簡単になります。

また、Pathオブジェクトには、ファイル名、拡張子、親ディレクトリを取得するメソッドが用意されているため、ファイルパスの取り扱いがより容易になります。

是非、Python開発でpathlibを使って、効率的なコーディングをしてみてください。

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

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になるよう心がけている(ただ、いつも長くなってしまう、、)

まとめ


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

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

参考になれば幸いです。

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