Photoruction工事中!

Photoructionの開発ブログです!

パッケージの管理ルールを制定してみた(第2弾)

はじめに

こんにちは!株式会社PhotoructionでAIエンジニアとしてインターンをしている渡邉圭太郎です。今回は、昨年末のアドベントカレンダーでの内容の続きで、CIルールについて執筆したいと思います。

アドベントカレンダーにおいて紹介しましたが、僕の所属するAIチームではよりAI開発やAI精度向上に力を入れるための改善点としてCI/CDの必要性が上がっていました。そこで、AI解析をパッケージ化やAPI化する際のCIルールを書きたいと思います。

構成図

今回制定したCIの構成図は次の図の通りです。また、Docker等のプロジェクト環境構築についてはアドベントカレンダーでの記事を参照してください。

f:id:photoruction_tech_blog:20220302182804p:plain

 

手順

  1. まず、cloudformationを用いてAWSのS3にリソースを作成し、テストデータを保存しておきます。
  2. 続いて、Github Actionsにおいて実行するためworkfileを作成します。workfileはプロジェクト配下の.github/workfilesディレクトリに配置します。
    ├── .github
    │   └── workflows
    │       └── **test.yml**
    ├── docker-compose.yml
    ├── Dockerfile
    ├── README.md
    ├── tests
    └── src
  3. 実行タイミングと環境変数を定義します。

    name: detection
    
    on: [ push, pull_request ]
    # ここでgithub actionsを走らせるタイミングを決められる。
    
    env:
    # 必要な環境変数を定義する
      AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
      CLI_AWS_ACCESS_KEY_ID: ${{ secrets.CLI_AWS_ACCESS_KEY_ID }}
      CLI_AWS_SECRET_ACCESS_KEY: ${{ secrets.CLI_AWS_SECRET_ACCESS_KEY }}
    
      ACCOUNT_ID: ${{ secrets.RD_ACCOUNT_ID }}
      AWS_ROLE_ARN: arn:aws:iam::${{ secrets.RD_ACCOUNT_ID }}:role/cli-role
    
      BUCKET_NAME: detection
    
      PIP_CACHE_DIR_DETECTION: /tmp/cache/pip_detection
    
  4. パッケージ内関数テスト用のjobを記述します。

    jobs:
      function-test:
        name: パッケージ関数テスト
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v2
    
          - name: Configure AWS credentials
            uses: aws-actions/configure-aws-credentials@v1
            with:
              aws-access-key-id: ${{ env.CLI_AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ env.CLI_AWS_SECRET_ACCESS_KEY }}
              aws-region: ${{ env.AWS_DEFAULT_REGION }}
              role-to-assume: ${{ env.AWS_ROLE_ARN }}
              role-duration-seconds: 1200
              role-skip-session-tagging: true
    
          - name: Download ocr key file from S3
    				# 解析テストに必要なファイルをS3からダウンロード
            run: |
              aws s3 sync s3://$BUCKET_NAME/ocr_key ./ocr_key --quiet
    
          - name: Cache detection pip
            uses: actions/cache@v2
            with:
              path: ${{ env.PIP_CACHE_DIR_DETECTION }}
              key: ${{ runner.os }}-detection-python-cache-${{ hashFiles('./pyproject.toml') }}
              restore-keys: |
                ${{ runner.os }}-detection-python-cache-
    
          - name: Build the docker-compose
            run: docker-compose up -d detection
    
          - name: detection install modules
            run: |
              docker exec detection /bin/bash -c "poetry install"
              docker exec detection /bin/bash -c "chmod -R 755 /root/.cache/"
    
          - name: detection test
    				# パッケージ内関数テストの実行
            run: docker exec detection poetry run pytest tests -s
    
  5. AI解析において多様なデータによるパッケージの評価検証を行うために、jobを追記します。ここでは、実施するテストケースごとにjobを作成しています。また、これらのテスト結果には閾値を設け閾値以上のスコアが得られない場合は失敗という結果と共にCI(/CD)がストップします。

    jobs:
    	function-test:
    		...
    	caseA_test:
    		...
    	caseB_test:
    		...
    

    テストケースごとのjobの例

    caseA_test:
        needs: function-caseA
    		# パッケージ内関数テストが成功しないと実行しない仕様にする
        name: caseA_test
        runs-on: ubuntu-latest
        env:
          TEST_DATA_DIR: caseA_test
        steps:
          - uses: actions/checkout@v2
    
          - name: Configure AWS credentials
            uses: aws-actions/configure-aws-credentials@v1
            with:
              aws-access-key-id: ${{ env.CLI_AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ env.CLI_AWS_SECRET_ACCESS_KEY }}
              aws-region: ${{ env.AWS_DEFAULT_REGION }}
              role-to-assume: ${{ env.AWS_ROLE_ARN }}
              role-duration-seconds: 1200
              role-skip-session-tagging: true
    
          - name: Download ocr key file from S3
    				# 解析に必要なファイル(ocr_keyファイルなど)をS3からダウンロード
            run: |
              aws s3 sync s3://$BUCKET_NAME/ocr_key ./ocr_key --quiet
    
          - name: Download test files from S3
    				# テストデータをS3からダウンロード
            run: |
              aws s3 sync s3://$BUCKET_NAME/test_sample/$TEST_DATA_DIR ./tests/dataset --quiet
    
          - name: Cache detection pip
            uses: actions/cache@v2
            with:
              path: ${{ env.PIP_CACHE_DIR_DETECTION }}
              key: ${{ runner.os }}-detection-python-cache-${{ hashFiles('./pyproject.toml') }}
              restore-keys: |
                ${{ runner.os }}-detection-python-cache-
    
          - name: Build the docker-compose
            run: docker-compose up -d detection
    
          - name: detection install modules
            run: |
              docker exec detection /bin/bash -c "poetry install"
              docker exec detection /bin/bash -c "chmod -R 755 /root/.cache/"
    
          - name: verification test
    				# 評価検証テストの実行
            run: docker exec detection poetry run python tests/verification.py -s
    
          - name: Upload result file from S3
    				# 評価検証結果をS3にアップロード
            run: |
              aws s3 cp ./tests/dataset/result s3://$BUCKET_NAME/test_sample/$TEST_DATA_DIR/result/$(TZ="Asia/Tokyo" date "+%Y-%m-%d_%H-%M-%S") --quiet
    

    おわりに

    今回、チーム内においてCI(/CD)ルールを制定したことにより開発のスピードがかなり上がったと感じました。また、改修の際のテストが以前に比べかなり早く終わり次の開発へ素早く移行することも可能となりました。

    個人的には、このような技術はさらに進化し出現するため最先端を走っていけるようなエンジニアになりたいです。ここまで読んでいただきありがとうございました。

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

iOSチームの運用ルールの変遷

はじめに

PhotoructionでiOS テックリードをしている數田です。

今回は私が加入してからのiOSチームの運用ルールの変遷の一部を振り返ります。

チームで開発するの運用ルールが定まっていなかったので、チームを運営する際の参考になる箇所もあるかと思います。

運用ルールで手動で行うことを増やすと漏れが発生するので、基本的に自動化できることしか取り入れていません。

運用ルールの変遷

ビルドが失敗する

一般的にはビルドが通る状態でPull Request(以下 PR)が作成されますが、ブランチをチェックアウトして手元でビルドすると失敗することが、多々ありました。

PRをレビューする都度、手元でビルドの確認するのはプログラマーの三大美徳に反します。

Bitriseを導入しPRのチェックが通っているものレビューしてマージする運用に変更しました。

マージタイミングがわからない

複数人で開発しているとPull Requestが多数作成され、すぐにレビューしてマージしたい衝動に駆られます。リリースタイミングが異なるPRも出てきて、間違ってマージしてしまう問題が発生してしまいます。

PRにリリース時期の記載がなかったため、確認に時間を取られていました。リリース時期を

PRのタイトルや説明に記載する方法が最初に思いつきますが、以下のような記述の揺らぎが発生します。

  • 2022年1月リリース
  • 2022年1月31日リリース
  • バージョン x.y.z

記述の揺らぎが発生せずGithubマイルストーンを設定することにしました。マイルストーンで絞り込めるようになり、優先的にレビュー、マージするPRがわかりやすくなります。

手動でマイルストーンを設定する運用を行っていると設定漏れが起きます。Dangerでマイルストーンが設定されているかのチェックを追加します。

PRの種類による絞り込み

PRのレビューする際に機能改修やバグフィックス、ライブラリのアップデートなど変更の種類によってレビューの観点が異なります。

開発用ライブラリのアップデートのPRなどすぐにマージしても問題ないものを一覧からタイトルのみで探さないといけないので多少手間がかかります。

PRの種類で絞り込めると手間が減るのでPRの種類の情報を付与する方法を検討した結果、ブランチ名で判別できそうなので、プレフィックスによってラベルをつけるGithub Action PR Labelerを追加しました。

現在iOSのプロジェクトでは以下の種類のラベルをつけて運用しています。

Feature: ['feature/*']
refactor: ['refactor/*']
Issue: ['issue/*']
bug: ['fix/*', 'bugs/*']
cre: ['bugs/*']

バグ解消

バグ解消のためCREチームがあり、PRはQAチームでテスト完了後にマージする運用となっています。CREが担当したPRは cre のラベルが付与されているの絞り込みできますが、テストが完了する前にマージしてしまうと、不具合が発生する可能性があるので、マージ前にテストの状況を把握する必要が出てきます。

PRにテストの状況を付与する方法を検討して、Github projectsでテストの状況をトレースすることで解決しました。

今後

基本的には自動化できる運用ルールを追加、見直しして開発で楽できるようにチーム運営を行っていきます。

常に改善し続けていくiOSチームと一緒に働く方お待ちしてます。

 

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

入社したらAndroid環境が良くなかったので良くした件について

はじめに

はじめまして。モバイルチームリーダーのAndroidエンジニアの齊藤です。

2019年10月にPhotoructionに入社し、現在で2年4ヶ月経ちました。

元々はSES会社に勤めていて、様々な企業に常駐でAndroidを中心にWebやサーバサイド等の開発をしていました。

Photoructionに入社した時点ではAndroidエンジニアが自分一人でした。

当初Android版Photoructionの開発は開発未経験の方が行い、その後業務委託やオフショアの方が機能開発・不具合修正・リリースを担当していました。そのため、開発基盤に特にルールが存在しない状態で、入社後に行ったのは開発環境や運用の変更でした。

今回はその時のことを振り返っていきたいと思います。

git-flowの導入

入社前の運用と問題点

Photoructionではバージョン管理にGitを使用していましたが、Androidチームでは特にgitの運用方法が決まっていたわけではありませんでした。

master, devブランチの他、エンジニアの名前ブランチフォルダだったり、バージョン別のブランチだったりと自由な運用がされていたため、どのブランチがどの内容なのか判断しづらい状況でした。

改善内容

そのため以下のようなgit-flowで管理することで、それぞれのブランチの役目を決めました。

master : プロジェクトの親ブランチで、リリース済みの最新ソースとなる。

develop : 開発用ブランチ。プロテクト対象で直Pushはできない。featureブランチのbaseとなり、featureの機能をマージすることで更新する。

feature : 機能開発用ブランチ。developからの作成が中心で、developに対して、機能を追加していくためのブランチ。「feature/xxxx」という形で、xxxxには機能に対する意味あるIDで管理する。

release : リリース用ブランチ。通常のリリースフローのためのブランチで、リリース可能な段階になったdevelopから作成される。「release/1.2.3」とリリースするバージョン名で管理する。

hotfix : 緊急不具合対応ブランチ。問題のあるリリース中のソースが存在するmasterブランチから作成される。「hotfix/1.2.4」とリリースするバージョン名で管理する。

社内だけではなく、業務委託の方やオフショアに対しても説明を行い、運用の徹底をしました。

featureブランチ名は、当時Trelloでタスク管理をしていたので、feature/dev-{カードID}で運用をするようにしました。

f:id:photoruction_tech_blog:20220202144602p:plain

 

※現在はタスク管理をBacklogやgithub issueで行っているためそれぞれのissueIDをブランチ名として利用しています。

deploygate対応

入社前の運用と問題点

元々社内の開発中及びリリース対象アプリの社内配布(テスト用)は、GoogleDriveにアップロードし、Android端末でダウンロードを行い、APKファイルからインストールする方法を取っていたため、端末によってインストールまでの操作が異なっているなど、手間が掛かり社内配信のハードルを感じました。

また、productFlavorsは接続先環境を切り替えるためにproduction, dev, alphaの3件存在しましたが、applicationIdSuffixが特に設定されていなかったため、一つの端末にインストールできるアプリが一つのみで、そのアプリがリリース用なのか開発中のものなのかを判断することが難しい状態でした。

f:id:photoruction_tech_blog:20220202150320p:plain

 

改善内容

deploygateへの移行をしました。配布も簡単で、アプリさえ入れておけば社内端末で好きなバージョンのアプリを入れることができるためです。

テスターさんとのやりとりも、「dev#123で確認お願いします」と伝え易くなり、テスターさん以外の社内のメンバーにも気軽に開発中のアプリを触ってもらえるようになったと思います。

また、applicationIdSuffixが特に設定されていなかったのでdevとalphaに対して設定しました。

f:id:photoruction_tech_blog:20220202145700p:plain

 

applicationIdSuffixを設定したことにより、それぞれが別のpackageNameになり、deploygateで同じアプリを環境違いでアップすることができ、一つの端末に環境別のアプリをインストールすることができるようになりました。

また、端末に環境別アプリがインストールできるようになったことで、どのアプリがリリース用・開発用かをわかりやすくするため、アプリのアイコンの色を変更しました。

f:id:photoruction_tech_blog:20220202145841p:plain

 

現在は会社やプロダクトのロゴが変更になったことにより、新アイコンになっています。

f:id:photoruction_tech_blog:20220202145901p:plain



アプリケーションのビルド

入社前の運用と問題点

アプリのビルドは、Android開発者がいなかったためオフショア側でビルドしたものを受け取り、それを配信する形を取っていたようです。社内にAndroidエンジニアがいなかったため、社内でビルドができていませんでした。

改善内容

配信方法がdeploygateになったこともあり、社内でアプリビルドが簡単にできるようにshellを作りました。

現在では、fastlaneで現在の開発ブランチのアプリを作成しdeploygateへアップロードしたり、github actionsで特定のPRコメントによってアプリをビルドしてdeploygateへアップロードする方法も運用しています。PRコメントでビルドする方法は、エンジニアだけでなく開発環境のないQAエンジニアも任意のタイミングでビルドしてアップすることができるので非常に便利になりました。

公開範囲の拡大と多言語対応

Photoructionは海外の建設現場での使用を考慮することが必要で、特にAndroid端末はiOSよりも海外でのシェアが高いので、重要なアプリとなります。

入社前の運用と問題点

公開範囲設定が2-3カ国しか設定されておらず、実際に利用される予定の地域が入っていなかったりと適切ではありませんでした。

また、海外での利用を考慮すると多言語対応も必要になりますが、アプリは日本語文言が全てstrings.xmlで管理されておらず、ソースコード内にハードコーディングされているものも多々ありました。

改善内容

公開範囲の拡大を行い、ハードコーディングされた日本語文言のstrings.xmlへの移行と多言語対応用のリストアップも行いました。

現在対応している言語は、日本語・英語・インドネシア語ベトナム語・中国語(繁体・簡体)です。

まとめ

入社直後は、Android版の開発環境がとても良いとは言えない状態だったため、最低限の形に直していきました。

Photoruction入社前に担当していた大手企業のアプリでも同じような状態だったこともあったので、Android版のリポジトリを見た時は特にガッカリしたとかはなく、そんなものだよね。という感じでした。

その後、メンバーが増えたり、豊富な知識を持った業務委託の方のご協力のもと徐々にAndroidの開発環境も良くなってきています。

他にも初期の頃にまともに動作しない不具合もありましたが、その話は次回以降お話したいと思います。今回はこのような記事でしたが、今後はもう少し技術寄りの記事にしたいです。

最後に

2021年のアドベントカレンダーAndroidチームの現在、そして今後のアーキテクチャについての記事がありますので、よろしければご覧ください。

 

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

ゼロイチからのプロダクト開発変遷

こんにちは!Photoructionで開発責任者をしています黒田です。

私がPhotoructionに関わり始めたのは起業して3ヶ月目の2016年6月で、かれこれ6年目を迎えました。

初期から関わらせてもらってきた中で、これまでの開発の体制や進め方などを中心にトピックスを交えながら立ち上げ〜現在に至るまでを時系列に振り返っていこうと思います。

目次


 

黎明期(2016年6月〜2017年)


プロダクトはもちろん会社の認知はほぼ無い状態。とにかく早く市場に進出する必要があった。

立ち上げ

  • 起業する前から代表の中島が1人で作っていたプロダクトをブラッシュアップしていく形で始まる。(実際はフレームワークから入れ直し)
  • プロダクトのプラットフォームはWEB、iOS
  • 開発は全員(当時3人。代表の中島、iOSエンジニア、私)で作るべき機能を決めて常にコミュニケーション取りながら朝から晩まで開発に明け暮れてた。
  • 各々役割はあるが市場調査からインフラ、デザイン、開発などなんでもやるスタンス。

β版リリース(2016年11月)

  • ローンチ前にして実際に現場で使っていただけるというお声をいただき、最小限の機能を用意してβ版をリリースする。

(自分たちが作ったプロダクトが初めて建設業の中に交わる実感が持てたことにすごく感動した記憶があります)

正式ローンチ(2017年7月)

  • プロダクトとして最低限業務で使える機能を用意して正式ローンチを行う。
  • このころになるとエンジニア人数も5人ほどになり、またプロダクトのプラットフォームもWEB、iOSに加えAndroidの開発も始まる。
  • 開発サイクルをどんどん回す必要があったためスクラム開発を導入する。
  • 1週間1スプリント、週1リリースのサイクル開発を進める。

ローンチ後

  • ビジネスサイドも立ち上がり、社員数も10人前後となる。

  • 少しずつ市場に認知を得始めるが、他社サービスと比べるとまだまだ劣ってる状態だったため同じ土俵に立つためにもひたすら機能追加を行う。

  • このころの開発チームとしてはプラットフォーム(WEB、モバイル)に関係なくワンチームでプロダクトのブラッシュアップに努める。

    f:id:photoruction_tech_blog:20220114145304p:plain

    当時は開発チームとしてベロシティを計りながらスプリントを回していた。

    • スプリントレビューは社員全員で行う。

拡大期(2018年〜2019年)


2018年

  • ユーザー数も徐々に増えていき、これに伴い要望数や不具合報告も増えいく。
  • エンジニアも総出で展示会に出店する(エンドユーザーの業務を直に聞いてキャッチアップし、それを踏まえて自分の言葉を通してプロダクトをイメージしてもらうことはとても良い経験でした)

  • AI開発の立ち上げ。

  • プロダクトとの領域を広げるために協業サービスとPhotoructionを連携させる開発する。

  • 全社導入にあたり、お客様の基幹システムとPhotoructionを連携さるためのAPIを開発し公開する。

  • プラットフォーム別(WEB、iOSAndroid)で開発チームを分ける。

    f:id:photoruction_tech_blog:20220114145925p:plain

  • スプリントレビューは全エンジニア+CS参加で行う。

2019年

  • 海外現場への導入などもあり多言語対応を行う。
  • 開発手法・体制の変更
    • エンジニア数も増え(10人前後)、スクラム開発のスプリント計画・レビューが形骸化していく。

    • ユーザーを獲得するための開発も増えていく中で、リリース計画を精緻にするためスクラム開発からウォーターフォール型へとシフトしていく。

      f:id:photoruction_tech_blog:20220114150201p:plain

    • 体制も開発プロジェクトを起点にした各職能に合わせたメンバーをアサインする手法を採用する。

      f:id:photoruction_tech_blog:20220114150516p:plain

       

成長期(2020年〜2021年)


2020年

  • PMグループ、デザイングループ、QAグループの立ち上げ。

    f:id:photoruction_tech_blog:20220117133956p:plain

  • 出社しての開発からリモート中心の開発へと切り替わる。

2021年

  • 既存の価値を守る部隊(トラブル、CSの技術サポート等)としてCREグループを立ち上げる。

    f:id:photoruction_tech_blog:20220114150652p:plain

  • より柔軟なDXによる価値提供を行うために、個社毎に用意したMicroServiceを利用して連携できる仕組みを構築する。

    f:id:photoruction_tech_blog:20220114150749p:plain

  • 機能のリニューアルなど大規模な案件が複数走る。

これから


開発プロジェクトを起点にしたウォーターフォールでの開発を行なってきた中で様々な課題も出てきました。

  • プロジェクト発生ごとにリソースの調整が必要
  • プロジェクトごとにチームが組成され開発が終了すると解散するため、チームワークが築けなかったり、機能数の増加や複雑性に伴いノウハウの蓄積がしづらくコミュニケーションコストが肥大化
  • チーム開発を行う上で意志を持った開発がしづらい などなど

これからの新たな開発体制に向けて

現在そういった課題を解決するためにも、体制や開発フローを見直して見直していっています。

直近では開発チーム(メンバー)を固定化し、領域内での開発により注力できるようなアジャイルチームにシフトしていきます!

  • ドメイン(注力領域)ごとのチームと、職能ごとのグループのマトリクス構造で構成。
  • ドメインごとのチームは、エンジニア・デザイナーなどの職能を横断したメンバーで構成され、ドメインごとの意志決定の促進を重視。
  • 職能ごとのグループではエンジニア横断でのノウハウの蓄積や横断課題の対処するための活動を実施し、相互成長や品質向上を重視。

f:id:photoruction_tech_blog:20220114151001p:plain

まとめ


立ち上げからの6年を思い返してみると(かなり端折ってますが(笑))色んなことがありましたが、現在はカオスな部分を最適化・仕組み化していくフェーズだと考えています。

まだまだ多くの組織課題や技術課題、プロダクトとしての課題も盛り沢山な状況ではありますが、プロダクトをはじめ全てはより良くしていくために取り組んでいます。

一つづつ紐解いて模索しながらもどうすべきかを実行してくことに共感や面白みを感じてくれる方、これからのPhotoructionの歴史を一緒に造り上げていってくれる方、ぜひお待ちしております!

最後まで読んでいただきありがとうございました。

 

Photoruction Advent Calendar 2021 編集後記

Photoruction Advent Calendar 2021 の実行委員長を務めさせていただきました。

Webエンジニアの田中です。

 

新年1発目の記事ですが、昨年末のアドベントカレンダー企画の振り返りからスタートしていこうと思います。鉄は熱い打つ必要がありますし!今年またアドベントカレンダー企画をする際に、きっと役に立つはず。。!

そもそもの経緯


2021年のアドベントカレンダーのスタートの背景としては、

Photoructionのエンジニア組織が外部から見えづらいということがありました。

その解決策の一環として、開発ブログを始めたかったからです。

 

なので、目的としては、

  1. フォトラクションの開発組織(体制・雰囲気)のことを知ってもらう
  2. 技術的な課題に対しての取り組み内容

と定めて、スタートしました。

 

他社さんがやられている、アドベントカレンダーに比べて、技術的なテーマは少ないと思われますが、テーマ設定から鑑みるに、目的達成です。。!

振り返ってみると、ブログは続けることが命!なので、逆にハードルを下げられて良かったと思います。

苦労した点


本企画の発足当初は、以下の不安な点がありました。

  • どの媒体を使うか、誰が運用の舵を取るのかなど、諸々のことが決まっていない中、スタート
  • 通常業務とは異なる業務を一方的にお願いすることになるので、正直25記事分集まるのか
  • 記事をどこまでチェックするか
  • スケジューリングなどをどこまでマネジメントするか
  • 各々の裁量に任せていたので、記事の品質の担保ができるかどうかは不透明

と、まぁ、社内でブログを立ち上げるあるある?が並んでました。

ただ、やってみなければ分からないことしかないわけなので、ベンチャーらしく、分からないなりに、走りながら考える形で進めてきました。

 

良かった点


上記の不安とは裏腹に、企画はスムーズに行きました。

  • メンバーから特に不満が出ることもなく、淡々と質の良い記事が量産されていきました
  • 弊社のエンジニアグループ(PMやQAも含む)総動員で、メンバーそれぞれが書ける記事、書きたい記事を熱意を込めて書いてくださりました
  • 様々な部門や経歴のメンバーの人となりや考えていることの違いに触れられて良かった
  • ちょっとしたお祭りとして、全社で見守られていた気がします
  • 当初の目的のPhotoructionのエンジニア組織や体制についてイメージが掴めるようなブログになっている

業務で取り組んだ事柄や課題の解決に関してを記事にして、知識の棚卸しに活用してくださったり、自身のキャリアや振り返りの一環して活用してもらったりと、本企画を有効活用してもらえたので、思ったよりも社内での評判は悪くないはず。。!笑

平日は毎日公開された記事を社内でシェアしていましたが、エンジニアグループ以外の部門のメンバーも覗いてくれてるみたいで、暖かく見守ってくださってました。(感謝感激)

 

今後のPhotoructionの開発ブログどうするか


もちろんですが、引き続き続けていきます!!

これからPhotoructionのメンバーになるかもしれない方もそうですし、ブログを書くメンバーにも楽しめる機会にできるよう頑張ります!(新年の抱負)

もし良かったら、他記事も覗いてみてください!!ではでは〜!

 

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

VIMで開発する

 

開発者の中でも黒魔道士しか使わないツールがあります。

Linuxサーバーのcrontabを更新する必要がある時または、設定ファイルを修正する時など、必ずどんなマシンにでも入っているエディターを使わなければなりません。しかしよくあることはWimしか入ってないことがあります。

Vimはエディターの中で使いづらいことや、小さなスクリプトだけならなんとか修正可能などと言われていますが、実際やろうとすると、結構効率よく開発もできます。

まずは、基本のVimで何ができるのかを紹介してから、プラグインを入れてみるとどこまでモダーンなIDEにできるのかお見せしましょう。

免責:これはあくまで個人的に「ほぉ、これは便利だね」と思った機能とプラグインだけです。

 

基本操作と知識

モーダルエディタ

Vimはモーダルエディタです。モードを切り替えて、ファイルの編集やコードの操作を行います。

デフォルトは Normal モードです。キーを打つとコマンドが実行されます。

一番よく知られているのは i キーを押すと Insert モードに切り替えます。

このモードで打つ字が入力されます。つまり、通常のエディタと変わりません。

Insert モードから Normal モードに戻るために Esc を打ちます。

: キーを打つとコマンドを打つことができます。

基本操作は vimtutor で勉強でき、これは日本語に翻訳されています。シェルで vimtutor ja を実行してみてください。

 

検索

検索はアクティブウィンドウの中で行います。

/ を打つと検索できます。つまり、 function getHolidays() 文字列を探すために /getHoli でマッチできます。打てば打つほど完全一致できます。

そして、コードを読む際に、カーソルオーバーして、 * を打つと文字列の検索となります。 ? を打つと、さかのぼり検索になります。検索の結果は n で次のマッチに飛び、 p で前のマッチに戻ります。

検索が終わったら、 :noh で検索ハイライトを解除できます。

 

バッファ、ウィンドウ、タブ

Vimのレイアウトアイテムの名前は普段のアプリケーションとちょっと違います。

バッファは基本的にファイルです。

ウィンドウはバッファを閲覧するGUIスペース。複数ウィンドウが同じバッファを違う箇所で開くことができます。

タブは簡単に言うと、ウィンドウのセットまたワークスペースと考えられます。

バッファを閉じると、このバッファを使うウィンドウが全て閉じます。

 

Vanilla VIMプラグイン無し)で開発

このセクションで、一般のVimと.vimrcで開発用のTipsを紹介します。

プラグインがなくても、ある程度効率よくコーディングができます。個人的パソコンまたはよく使うサーバーであれば、ちょっとぐらい設定ファイルを更新して、Vimの機能を開放できます。

設定ファイルは通常 $HOME/.vimrc です。

早速ですが、下記の設定を追加します。

 

""""" あった方がいい設定 """""
" これでいろいろな言語のハイライト機能をオンにする
syntax on
" ファイルタイプに応じてオート設定
filetype on
filetype indent on
" vimの反応速度を上げる(screen redraw)
set ttyfast
" いつもステータスを表示する
set laststatus=2
" backups フォルダを作成する
silent !mkdir -p ~/.vim/backups
" swap ファイルフォルダ
set directory=~/.vim/backups//
" バックアップフォルダ
set backupdir=~/.vim/backups//
" 編集されたファイルを保存しなくても、他のファイルを開ける
set hidden

" タブをスペースに
set expandtab
" タブのサイズと自動インデント幅を4文字に
set tabstop=4
set shiftwidth=4
set softtabstop=4

""""" エディター """""
" 長い行をwrapしない
set nowrap
" 行数を表示する
set number
" オートインデントを有効に
set smartindent
set autoindent

" 打っている最中検索を行う
set incsearch
" 小文字のみで検索すれば、ケースに関わらず検索する。大文字を使えば、ケースマッチを有効に
set smartcase
" 検索マッチをハイライトする
set hlsearch

" 貼り付けモード切り替えキー(勝手にインデントをしないモード)
set pastetoggle=<F2>
" diffを縦で開く
set diffopt+=vertical

" 保存する際に末尾のスペースを消す
augroup Cleanup
	autocmd!
	autocmd BufWritePre * :%s/\\s\\+$//e
augroup END

""""" レイアウト """""
" 縦スプリットを下に開く
set splitbelow
" 横スプリットを右に開く
set splitright

""""" netrw (ファイルブラウザ)"""""
" バナーメッセージを非表示
let g:netrw_banner=0
" スプリットファイルブラウザを開くとウィンドーのサイズ設定(%)
let g:netrw_winsize=50
" プレビユーを縦スプリットで開く
let g:netrw_preview=1
" ツリー表示
let g:netrw_liststyle=3

Netrw:ファイルブラウザ

Vimはすでにファイルブラウザがついています。

全画面で開く: :Ex

スプリットして、下に開く: :Hex

スプリットして、左に開く: :Vex

タブで開く: :Tex

操作はかなり単純で、通常の移動+エンターキーでフォルダを展開またはファイルを開きます。

f:id:photoruction_tech_blog:20211220094501j:plain

p を打つとプレビューウィンドウを開きます。

Ctrl+w z でプレビューを閉じます。

R でファイルまたはフォルダの名前編集ができます。

v を打つとファイルをスピリットで開きます。

 

画面スプリット

新しいウィンドウを右に開く: Ctrl+w v

新しいウィンドウを下に開く: Ctrl+w s

カーソルを別のウィンドウに移動: Ctrl+w [移動キー]例えば、右のウィンドウに移動する: Ctrl+w l

アクティブウィンドウを拡大する(他のウィンドウを閉じる): Ctrl+w o

アクテイブウィンドウを閉じる: Ctrl+w q

もちろんスプリットの中にさらにスプリットもできます。どんどん読みづらくなりますけどね。

f:id:photoruction_tech_blog:20211220094737j:plain

 

タブ機能

新しいタブを作成する: :tabnew

次のタブに移動する: g t

前のタブに移動する: g T

他のタブを閉じる: :tabonly

タブを閉じる: :tabclose

タブの使い方は色々有るのですが、個人的にタブ毎にアプリケーションコードとのファイルに対するテストファイルを開くことが多いです。

タブ1:
- BookingController
- BookingControllerTest
タブ2:
- BookingLogic
- BookingLogicTest

オートコンプリート

はい、一応単純なオートコンプリートが付いています。

非常にスマートというわけではないが、一応開いているバッファのなかを分析して、合いそうな文字列で推奨するような機能です。

ようするに、複雑な変数名があれば、問題なくこれで入力できます。

Insert モードで Ctrl+n を打つとオートコンプリートが表示されます。選択1つしかなければ、表示せず自動入力されます。 Ctrl+n で次の選択(下)に移動して、 Ctrl+p で前の選択(上)に戻ります。

f:id:photoruction_tech_blog:20211220094828j:plain

f:id:photoruction_tech_blog:20211220094841j:plain

 

タグでナビゲーション

tags ファイルが存在したら、vimがそのタグファイルを読み込んで、それぞれの箇所に飛ぶことが可能です。カーソルを文字列にオーバーして、 Ctrl+]でタグの定義箇所に飛べます。 Ctrl+t で元のファイルに戻れます。たまに同じタグに複数定義箇所が存在します。その時、 g] を打って、どのファイルを開くのを選択できます。 :tags <タグ名> でも使えます。

f:id:photoruction_tech_blog:20211220095106j:plain

タグファイルを生成するために ctags と言うツールをインストールする必要があります。コードが変わるとまた生成する必要があるので、ちょっと使いにくいです。ただし、プラグインを使うと自動化できます。そして、あまり変わらないコードだったら、一応手動でもタグファイルを生成する価値があります。

そして、タグナビゲーション機能をVimのヘルプで使えます。 :help でアクセスでき、リンクを Ctrl+] または g] で開けます。

 

ターミナル

Vim 8 以降だと、ターミナルが付いています!

:terminal で起動できます。ターミナルはデフォルトで Insert モードです。

Normal モードに切り替えIMはエディターの中で使いづらいやるために Ctrl+w N を打つ必要があります。

また Insert モードに戻るには、通常通り i を打てば良いです。

Normal モードでは通常の動き、コピーなど、すべての機能を使えるので、便利です。

ターミナルを専用タブで開いても便利です。

もちろん、 vim 自体を Ctrl+z でバックグランドに落としてもいいです。

そしてシェルから fg を実行するだけで復活できます。

 

セッション

例えばVSCodeを開く時、最後閉じた状態のままでまた開きます。

vimでも似たような機能が存在します。

:mksession! を実行すると同じフォルダに Session.vimファイルが作成されます。

このファイルをロードするとファイル作成時の状態に戻ります。 :source Session.vim で実行できます。

またはシェルでエディタを実行する際に、 -S パラメタを追加すると自動的に Session.vim をロードします。

このコマンドの弱点は手動で実行する必要があることです。 .vimrc でキーマッピングを追加したら、自動コマンドを追加するのが便利です。

個人的に、専用プラグインに任します。

 

プラグインを入れましょう!

プラグインを使うと、機能は爆発的に広がります。

プラグイン管理

vim 8 が既にプラグイン管理ができるのですが、個人的には VimPlug を気に入り使用しています。

プラットフォームによってやり方がちょっと異なりますが、基本的に、プラグインのコードを autoload フォルダに入れればOKです。

そして、 .vimrc の中で

call plug#begin()
call plug#end()

のブロックを作って、欲しいプラグインをここに入れれば簡単に管理できます。

流れは:

  1. Plug 'xxxx/xxxx' の行を .vimrcbegin...end の中入れて
  2. vim を起動して(またはリロードする)
  3. :PlugInstall を実行する

たまに :PlugUpdate を実行するだけで更新できます。

 

基本設定とUI

デフォルト設定の見直し

まずはVimのデフォルト設定を軽く変えた方がいいです。

これは tpope/vim-sensible に任せます。

ステータスバーのレベルアップ!

VimのデフォルトUIは静かで邪魔にならないのですが、たまにちょっとスパルタ過ぎます。

ステータスバーを vim-airline/vim-airline で拡張します。

そして、より格好よくするために vim-airline/vim-airline-themes も入れます。

vim-airlineでいろいろな情報が目の前に現れます。モード名、ブランチ名+ファイル変更まとめ(インサート、変更、削除の行数)、ファイルタイプとエンコード、ファイルタイプ等。

スクショや機能の詳細と設定はGithubで確認するのはおすすめです。

カラースキーム

あくまで好みの問題ですが、自分は sainnhe/sonokai のダークカラースキームが好きです。

VimPlugでの管理も簡単です!

そして、微調整のため(カラースキームのオプションなど)のため、設定ファイルに下記を追加します。

" ダークモードは正義!
set background=dark

" フルカラーターミナルだとOKです
set termguicolors
" カラースキームオプション
let g:sonokai_style = 'shusia'
let g:sonokai_enable_italic = 1 
let g:sonokai_transparent_background = 0 
let g:sonokai_diagnostic_text_highlight = 0 
let g:sonokai_diagnostic_line_highlight = 0 

" カラースキーム選択
colorscheme sonokai
" 更にオプション(他のプラグインと連携)
let g:airline_theme = 'sonokai'
let g:airline#extensions#coc#enabled = 1 

 

共通コードツール

このカテゴリは通常のIDE機能をVimで再現できるプラグインについてです。

Ctrl+P

それぞれのIDECtrl+pでファイルを開いたりができます。もちろん、Vimでもできます!

そのために ctrlpvim/ctrlp.vim を入れましょう。

そして、興味のないファイルを省く設定を追加します

" CtrlP
set wildignore+=*/tmp/*,*.so,*.swp,*.zip     " MacOSX/Linux
set wildignore+=*\\\\tmp\\\\*,*.swp,*.zip,*.exe  " Windows

let g:ctrlp_custom_ignore = {
  \\ 'dir':  '\\v[\\/](\\.(git|hg|svn)|node_modules|vendor)$',
  \\ 'file': '\\v\\.(exe|so|dll)$',
  \\ 'link': 'some_bad_symbolic_links',
  \\ }

 

ワードハイライト

カーソルがオーバーしているワードをハイライトするプラグインも個人的に好きです。

それは RRethy/vim-illuminate で解決します。デフォルトはアンダーラインでマッチを表示するのですが、ブロックハイライトが好みです。

" ハイライト
hi link illuminatedWord Visual

 

セッション管理自動化

さすがに毎回 :mksession!を実行するのは手間がかかります。もちろんそのためのプラグインがあります!早速入れましょう: tpope/vim-obsession

Tim Popeのプラグインが必要なパラメタのみを保存しています。

そして、セッションのトラッキングを開始したい時: :Obsess を実行するだけです。 -S フラグを使ってセッションをロードしたら、 :Obsess を実行する必要はありません。

注意:バッファを開く・閉じる際に Session.vim ファイルが更新されます。したがって、ステートを保存するために全てのバッファを一括で閉じる必要があります。すなわち、 :q ではなく :qa で終了しましょう。

タグファイル生成

ctagsを自動的に実行してくれるプラグインの登場です!

では ludovicchabant/vim-gutentags も入れましょう。プロジェクトが大きかったら、タグ生成は時間がかかる場合あります。

ローカルvimrc

プロジェクト毎設定を変えて欲しい時がある場合、 embear/vim-localvimrc で設定の微調整ができます。

このプラグインを入れると 各プロジェクトに .lvimrc ファイルを作って、設定を入れて、この環境だけで適用します。

デフォルトは毎回「 .lvimrc の設定をロードしていい?」と聞かれてしまうので、下記の設定で、ファイルが変わらない限り、承認を覚えてくれます。

" lvimrc
let g:localvimrc_persistent = 1

 

特にデバッガの設定や、ソースコードフォルダマッピングのためにこのプラグインは非常に便利です。

ソース管理対応(Git)

もちろんターミナルでいちいち実行して、何が変わったのを確認できますが、流石に大変ですね。

エディタで一目で分かるようにしたほうが良いに間違いありません。

Vim-GitGutter

airblade/vim-gitgutter は左側の行目のさらに左にファイル変更の印を入れてくれます。

f:id:photoruction_tech_blog:20211220095336p:plain



上記のサイドバーでは - は削除、 ~ は編集、 + は追加と明確に変更の内容と箇所を示します。変更の内容は \ h p で確認できます。

もちろん印、色など、全てカスタムできます。他の機能もたくさん有ります。

詳細はvim-gitgutterのGithubで確認するおすすめします。

" vim-gitgutter
if exists('&signcolumn')  " Vim 7.4.2201
  set signcolumn=yes
else
  let g:gitgutter_sign_column_always = 1 
endif
set updatetime=200
let g:gitgutter_override_sign_column_highlight = 1

 

Vim-Fugitive:いろいろなツール

tpope/vim-fugitive からインストールできます。

このプラグインはいろいろなGit機能をWrapしています。全部説明する余裕はないですが、例えばgit blameをvim内で確認できたり、ファイルの古いバージョンと比較したりできます。

詳細はGithubページで確認ください。

ViMagit

Magit( jreybert/vimagit )パネルを開くとワークスペースの様子を確認や、変更をステージングスペースに追加するもしくは捨てるやコミットもできます。

VSCodeのGitタブみたいな感じです。ファイル単位だけではなく、ハンク(変更ブロック)単位と行単位も対応します。

https://user-images.githubusercontent.com/533068/28827790-ee0ec640-76ce-11e7-840b-10a4f5e4eae4.gif

下記の追加設定で \ g sマッピングします。

" vimagitパネルを開く
nnoremap <leader>gs :Magit<CR>       " git status

 

スマートコードコンプレッション

VimVSCodeみたいにスマートにできますか?もちろんですとも!

このゴールを達成するためにLS(Language Server:言語サーバー)を使います。

LSとは何でしょうか?まぁ、簡単に説明すると、裏で動いている特定言語サーバープロセスとやり取りして、コードの様子を確認し、オートコンプリート選択肢を計算などします。

このLSとやり取りをするために、LSP(LSのプロトコル)を扱うプラグインが必要です。

インストール

このプラグインの名は neoclide/coc.nvim です。

プラグインをインストールするだけでは足りません。使いやすくするために、設定も更新しないといけません。

おすすめの設定はこちら:https://github.com/neoclide/coc.nvim#example-vim-configuration

全部必要と言うわけではないですが、デフォルトとして安定で使いやすいです。

運用になれてから設定変更するのがおすすめです。

言語サーバー登録

CoCプラグインを入れるだけで、なにもできません。言語サーバーが必要です!

そのためにそれぞれのCoC拡張をインストールする必要があります。

基本的に、https://github.com/neoclide/coc.nvim/wiki/Language-servers に参考しながら、インストールすべきです。

その他、おすすめのやり方は vimrc で登録するのではなく :CocInstall で管理することです。

例えば、Javascript/TypeScriptサーバーをインストールするには

:CocInstall coc-tsserver でできます。

念の為、一旦vimを閉じて、開いたら、シンタックスチェックやオートコンプリートが使えるはずです。

f:id:photoruction_tech_blog:20211220095429p:plain

f:id:photoruction_tech_blog:20211220095444p:plain

 

まとめ

ここまで読んでいただけたら、「よく頑張ったね!」と感謝致します。

Vimは間違いなくちょっと変わったツールで、だいぶ古いイメージがあるのですが、モダーンな開発ツールとしても使えます。

もちろんVSCodeや他のIDEVimっぽい動きはできますが、中途半端なできで使い物になりません。これで満足できませんでした。

Vimでないエディタを毎日使って涙を流している皆様のために、この(かなり雑な)ガイドを作りました。自分に合う開発環境を作る踏み台になれば幸いです。

 

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

corporate.photoruction.com

www.wantedly.com

パッケージの管理ルールを制定してみた

こんにちは!今年の5月から株式会社PhotoructionでAIエンジニアとしてインターンをしている渡邉圭太郎です。 Photoruction Advent Calendar 2021の24日目の記事です。

はじめに

僕の所属するチームではパッケージ管理をgithubで行っていましたが、特に管理ルールはなくリポジトリの扱い方はメンバーによって異なっていました。加えて、CI/CDを積極的に行っていこうという意見がチーム内で上がっていました。特にチームの核であるAIモデルの精度向上などAI開発の方に時間を割きたいというメンバーが多かったからです。

そこで、この度チーム内でのパッケージ管理ルールを制定したのでその内容を一部紹介します。

ブランチ戦略

ブランチ戦略とは

ブランチ戦略とは、Git上でブランチを分けて作業を並行して行う際にそのブランチを計画的に作成し運用していくことである。定めておくことでチーム開発での開発の柔軟性とコードの一貫性という2点が確保できる。

Github Flow

ブランチ戦略自体はたくさん考案されているが、今回はGithub flowというブランチモデル(master, develop, 各topicごと...)を採用した。その内容を簡単に下図に示す。

f:id:photoruction_tech_blog:20211217104819p:plain
git flow

masterブランチを本番環境ブランチ、developブランチを開発環境とし、エンジニアが個々に開発を行う場合はbranch1, branch2, ...のように分けていく。

この運用方法では以下の基本ルールがある。

  1. masterは常にデプロイ状態にする
  2. masterから必ずtopicブランチを切りmasterに直接コミットすることがないようにする
  3. ブランチは定期的にpushする
  4. pull requestを用いてコードレビューを行う
  5. コードレビューが完了したらすぐにmergeする

様々な記事を読むとこの他にもカスタムルールを制定している場合もあるようなので、ぜひ自チーム流にブランチ戦略を制定してみてほしい。

リポジトリ事前設定

前項で挙げたルールのうち1, 2そしてCIに関してはGithubリポジトリの設定項目から事前に制約をかけることができる。

今回は1例として、masterブランチへCIを成功したブランチのみmergeを許す方法を記載する。

  1. "settings" → "Branches"と選択

    f:id:photoruction_tech_blog:20211217105033p:plain
    github_setting01

  2. "Branch protection rules"から"Add rule"を選択し、下図のように設定をする。

    具体的には、リポジトリ管理者を含めmainブランチにおいてCIを成功させないとmergeできないように設定している。また、この設定によりmainブランチへの直pushも防いでいる。

    f:id:photoruction_tech_blog:20211217105127p:plain
    github_setting02

  3. "Save Changes"(作成時は"Create")を選択して終了

また、他の設定項目については詳しくはこちらを参照。

開発環境のコンテナ化

コンテナ化と実装理由

コンテナ化とは、ソフトウェアのコードをライブラリやフレームワークなどの依存関係にあるすべてのコンポーネントとともにパッケージ化し、それぞれの入れ物、「コンテナ」に隔離することです。(コンテナ化とは

また、開発環境のコンテナ化を行うと以下のことができる様になる。

  1. チェックや改修の際の環境構築を楽になる
  2. osのバージョン等に左右されずに開発を行える

以上の理由から開発環境のコンテナ化を行うこととなった。

dockerでのコンテナ化実装

今回コンテナ化にはDockerを用いて行う事になった。そこで実際の実装例を紹介する。

なお、Dockerについての事前知識については以下を参照。

  • Dockerコンテナーの概要

  • pc内にDocker Desktopをインストールする

  • Dockerfileとdocker-compose.ymlを用意する

    フォルダ構成

     ├── docker-compose.yml
     ├── Dockerfile
     ├── README.md
     └── src
    

    Dockerfile

     FROM python:3.8
    
     ENV APP_PATH=/code \
         PYTHONPATH=.
     # 開発物のソースコードはcodeデイレクトリ下に配置する
    
     WORKDIR $APP_PATH
    
     RUN apt-get update && \
         apt-get upgrade -y && \
         pip install poetry
     # コンテナのセットアップ
    
     COPY . .
    
     RUN poetry install 
     # 必要なパッケージ等をインストールする
    
     EXPOSE 8080
    

    docker-compose.yml

     version: '3.8'
     # 使用するDockerEngineリソースに適応するバージョンを指定する。
    
     services:
       test_src:
         container_name: test_container
    
         build:
           context: .
           dockerfile: ./Dockerfile
         ports:
           - "8080:8080"
             tty: true
         volumes:
           - ./src/:/code/src
           - ${PIP_CACHE_DIR_WORKER:-cache-test}:/root/.cache
    
     volumes:
       cache-test:
    

    なお、さらに詳しい引数等の内容に関しては、以下のドキュメントを参照。

  • 必要なファイルの準備ができたらDockerfileとdocker-composeを使用してコンテナを構築する

     docker-compose up -d --build test_src
     # イメージのビルド
    
     docker exec test_container poetry install
     # 必要なパッケージのインストール
    
     docker-compose up -d
     # すべてのコンテナの起動
    

これだけで環境のコンテナ化が完了する。

あとは、各々開発をゴリゴリすすめる。

まとめ

本記事では、実装例を紹介することを目的としたため基礎知識について深く解説できなかったので、その部分についての詳細は参考文献を参照してください。また、こうした方がより使いやすい等ありましたらぜひ教えて下さい!

パッケージ管理ルールを制定したことでチーム開発内で無駄に考えることが減ったと感じます。より開発自体に注力できる様になったのは良いことであると感じました。

また個人的には、チーム開発に関することは個人で行うには限界があったので、インターンという立場でこのようなことが学べたのはとても勉強になりました。これからも開発を頑張っていきたいと思います!

参考文献

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

corporate.photoruction.com

corporate.photoruction.com