Photoruction工事中!

Photoructionの開発ブログです!

入社したら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

ローカルでAPI Gateway, Lambdaの構成を再現する

こんにちは!株式会社Photoruction AIグループでエンジニアをしています酒井です。 Photoruction Advent Calendar 2021の23日目の記事です。

導入

APIGateway, LambdaのサーバレスアーキテクチャでWebAPIを開発する際、APIのレスポンス確認のために都度、クラウド上にデプロイするのは手間がかかります。

そこでServerlessFrameworkというフレームワークとserverless-offlineというプラグインを使用してローカルでレスポンスを確認できる環境を整えました。

ServerlessFrameworkとは

serverless-offlineとは

  • ServerlessFrameworkで使えるプラグイン
  • ローカル環境でAPI Gateway + Lambdaの構成を再現することができる

実施内容

クライアントによる「APIGateway」へのPOSTリクエストをトリガーにして、「Lambda」で定義した関数を実行することを想定しローカルでの開発環境を整える。 f:id:photoruction_tech_blog:20211217160020p:plain

手順

1. ServerlessFramework、serverless-offlineのインストール

$ npm install serverless
$ npm install --save-dev serverless-offline

2. プロジェクトの作成

sls create -t <テンプレート名> -n <プロジェクト名>でプロジェクトを作成します

ServerlessFrameworkが提供するテンプレートはこちらを参考にしてください

今回は aws-python3を使用しました。

任意のディレクトリに移動したあと、以下を実行します。

$ sls create -t aws-python3 -n serverless-sample

すると、ディレクトリ内に handler.pyserverless.ymlが作成されます

$ ls
handler.py   serverless.yml

3. handler.pyを編集する

  • handler.pyにLambda関数を定義します。
  • デフォルトでは以下のようにシンプルな関数 helloが定義されています。
import json

def hello(event, context):
    body = {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "input": event
    }

    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response

4. serverless.ymlを編集する

以下の設定を行います。

  1. functionsのhelloにeventsの追加
  2. 使用するプラグイン(serverless-offline)の記述
service: serverless-sample # プロジェクト名
frameworkVersion: '2'
provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
functions:
  hello:
    handler: handler.hello # handler.pyの関数helloを実行する

    # 追加
    events:
      - http:
          path: /test # <- 任意
          method: post # <- POSTリクエストをしたので post を指定

# 追加
plugins:
  - serverless-offline

5. 起動

以下コマンドでプロジェクトを起動すると、エンドポイントが表示されます。

$ sls offline start
 
   ┌─────────────────────────────────────────────────────────────────────────┐
   │                                                                         │
   │   POST | http://localhost:3000/dev/test                                 │
   │   POST | http://localhost:3000/2015-03-31/functions/hello/invocations   │
   │                                                                         │
   └ ────────────────────────────────────────────────────────────────────────┘

レスポンスを確認する

  • エンドポイントに対して {"name": "yamada"}というデータとともにPOSTリクエストを送ってみます。
  • すると handler.pyに定義したbodyの内容が正しく表示されます。
  • データも正しく送信できていることが分かります。
$ curl -X POST -d '{"name": "sample"}' http://localhost:3000/dev/test
{"message": "Go Serverless v1.0! Your ...", "input": {"body": "{name: yamada}", ...}

まとめ

ServerlessFrameworkのserverless-offlineというプラグインを使うことでローカル環境でAPIのレスポンスを確認することができました。

開発していく中で挙動を確認するために都度、クラウド上にデプロイする必要がないので時間短縮につながりました。

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

corporate.photoruction.com

www.wantedly.com

木工(家具)職人とAIエンジニアの共通するところ

目次

  1. はじめに
  2. 物作り
    1. 早いということ
    2. 綺麗だということ
    3. 正確だということ
  3. 木工職人と工場長、エンジニアとPMの関係性
  4. 共通しないこと
  5. 最後に

1.はじめに

2021年も早いもので残すところ2週間くらいとなり、「今年も一年早かったね」なんて言葉を言ってみたり聞いたりすることが多くなってきました。今冬は寒くなるんでしょうか、雪は降るのかな、来年の干支ってなんだっけなどと考えたりしてます。

さて、私はというともうすぐAIエンジニアとなってまる2年が経とうとしています。

社会人になってから飽きることなく繰り返してきたこの「今年も一年早かったね」とともにこの2年間を振り返りつつ、16年ほど携わった前職の木工(家具)職人と現在のAIエンジニアの共通することってなんだろうを考えてみたいと思います。


2.物作り

「段取り八分」

職人をしているとよくこの言葉を聞きます。

段取り(準備)さえしっかり出来ていれば仕事の8割は出来たようなもの、みたいな意味です。

8割は言い過ぎだろという思いが頭を掠めまくっていましたが、経験を重ねれば重ねるほどこの言葉の意味を意識することは多かったように思います。

木工職人にとって**「早くて綺麗で正確に」**という絶対的に正しい結果を追求する上で「段取り八分」(いかに効率的なプロセスを辿るか)はもっとも重要な考えの一つだと思ってました。

AIエンジニアと木工職人の間には、アナログとデジタルの違いはあるものの「モノを作る」という大きな共通点があります。

木工職人にとって大切だと思っていたことを半ば無理やりAIエンジニアにとって大切だと思うことに結びつけてみたいと思います。

木工は作り手が図面をもらった時点で何を作るかは明確に決まってます。(まれに途中で変更があったり、一部決まっていない中進めることもありますが、、、)

製作スタートと同時に数時間は図面と睨めっこしながら、部分的な詳細図を描き(組み立て説明書を自分で考え思考を整理し書き起こすみたいな作業)、完成形や製作工程を頭に叩き込み、最短距離でゴール(完成)するにはどうすべきかを考えます。

1つの家具・什器(店舗やオフィスの家具)でも作り方は何通りかあり、製作物の大きさや難易度によって、どの手法をとるかで手間と時間が大きく変わります。この辺りは経験と知識が大きくモノをいいます。(ゴールを「目的」に置き換えるとその時考えてたことはphotoructionのvalueである「目的逆算」に近い気がします)

早いということ

そこで家具や什器をコードに、鉋(カンナ)・ノコギリ・電動工具等をPCに置き換えてみると、この「早くて綺麗で正確に」という価値観は職人からエンジニア業務への延長線上にしっかり乗っかってきます。

IT業界でも「脱・完璧主義」や「7割の完成度」を意識するみたいなことはよくいわれると思います。エンジニアとしても早ければその分多く開発できるし、開発コストも抑えることができるし、組織にとってもメリットは多いはず、やはりエンジニアとしても早いは正義だと(個人的に)思います。

綺麗だということ

AIエンジニアが使用するプログラミング言語PythonにもPEP8というコーディングスタイルガイドがあります。

その目的は読みやすくて、可読性が高く、一貫性のあるコードを書くためにこういうことは守ろうね、みたいなことが書いてあります。Python開発者たちがコードを読みやすく綺麗に書くことを非常に重要だと考えていることをスタイルガイドを通して感じることができます。

開発において、一度リリースしたからといってコードは未来永劫そのままか??というとそんなことはなく、開発したものが使い続けられる限り改修は行われます。その際、開発者本人が改修するとは限らない上に場合によっては、開発者が退職しているケースもあるかもしれません。改修担当者にとってどのコードが何の目的で書かれているかわかりやすければわかりやすいほど、作業も進みます。コードが他者から見てわかりやすいと改修やデバッグする上で作業性を大きく左右する、保守性において重要ではないかと考えます。

正確だということ

AI開発の最終段階では、それまでの開発内で使われていた学習データ(教師データ)とは別に使われていないテストデータをもとに評価検証を行います(開発したAIモデルの精度や処理時間など算出するため)。

リリースした後に扱うデータがテストデータと同じようなものかというと、そんなことは全くなく、開発中には遭遇していない未知のデータに対してもロバスト(頑健)であることが求められます。

ロバストな開発ができるどうかは開発物の品質を大きく左右します。


3.職人と工場長(現場監督)、エンジニアとPM

関係性が似ていると感じることは多いです。

(*木工職人の場合、やりとりの多くは工場長や制作担当リーダーみたいな人とが多いんですが、他の職方だと監督とやりとりする場面が多いと思うので置き換えた方がわかりやすいかもしれません)

制作においては工場長はあくまでもハブです。というと語弊があるかもしれませんが、工場長は内装業者から案件を受注し家具図・什器図をもらい図面だけでは読み取れないこと、スケジュール、お金に関することなどを内容業者と調整します。そして、各制作物ごとに工場長が担当の職人と打ち合わせを通し、制作物の詳細やスケジュールを共有します。職人は制作中に図面に書かれておらず、自身では判断できないことがよくあります。その際は工場長を通し内装業者に問い合わせを行います。。

とざっくりですが、ここまで書いているとエンジニアとPMの関係も同じとはいわないまでも近いと感じる人もいるのではないかと思います。

私はAIエンジニアしか経験がないので、他のエンジニアがどうかはわかりませんが、少なくとも木工職人と工場長、AIエンジニアとPMの関係性は共通点が多く、エンジニアとして仕事を始めた早い段階からエンジニアとPMの間に境界線を引いていたと思います。こっからここは、エンジニアが考える、そっから先はPMの領域、、、みたいな感じに。

ただ、この境界線の置き所が難しく、微調整を繰り返しながら最適なやり方を模索している途中です。

4.共通しないこと

思いつくことはまだあり時間をかけるとまだまだ書けそうですが、そろそろ今行っている開発に戻った方が良さそうなので、最後に共通していないことを書きたいと思います。

一番大きい違いは、グループやチームの存在を近くに感じるかどうかではないでしょうか。

木工職人としてはあまり意識することはなかったように思います。(途中、工場長みたいなこともやっていた時期があり、その際は作ることはどうしても二の次になりチームや組織としてどうするかみたいなことは考えていたような気がします)

Photoructionではいくつかの部署があり縦横無尽に連携していると思います。そういった組織の複雑性みたいなものは木工時代にはなかったので、新鮮であり勉強になることが多く、他者との関わり方みたいな部分で意識の修正が必要でした。

私に開発の話が届くまでに社内で幾つかのプロセスを経てきます。そのプロセスの具体的な内容まではわかっているわけではないですが、色々なプロセスの内容に触れる機会があると小説の一部を読んでいるようで面白いなと感じることもあります。

(あまり関係ないかもしれないが、組織人としてPhotoructionが掲げているvaluesに「敬意尊尚」とういうものがあり、それがどういったものかを共有する勉強会の参考図書となっていたTeam Geak(Googleギークたちはいかにしてチームを作るのか)は非常に参考になり、これから何度も読み返そうと思う)


最後に


思いつくままつらつらと書きましたが、技術的なことを書くにもう少し時間が必要だと思ったので、あまり考えずに済む題材をチョイスしましたが思っていた以上に時間がかかってしまった。

おが屑に塗れながらにしろ椅子に座ってキーボードをカチャカチャするにしろ、物を作るというのは面白いものですね。

これをエンジニアが読んでためになるとはあまり思えませんが、最後まで読んでいただきありがとうございますmm


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