プロダクトの成長を阻害しない技術的な意思決定を行えるリーダーになる
ソフトウェアの開発速度はさることながら、メンテナンス性というものも同様に事業の速度に直結する欠かせないものであると考えています。
当初の意思決定を誤ってしまうと、後々の新規開発での速度・品質の低下や、メンテナンスコストの肥大化を招く危険性があります。
この意思決定を行うには一朝一夕の経験では足りず、またこの意思決定に必要な経験が満ち足りる日は到来しないと思っています。
それでも判断を誤るとどうなるか、ということについて関心を持ち、副業含め多くのプロジェクトに関わってきたことで、人並み以上にその大切さを噛み締めてきたという自負があります。
チームでの開発の弊害となりうるリスクを事前に対処することにやりがいを感じており、また正しい意思決定をし、チームとして成果を出し続けられるような、イネイブリング領域にも携わるテクニカルリード、あるいはプロジェクトマネージャに近しい領域の(事業推進にコミットする)エンジニアリングマネージャを理想像としています。
シード期の出資を数度受け、リリースを目標とするプロダクトが決まったフェーズのスタートアップに参画し、所謂 CTO が担う領域に携わりました。
(CTO を打診されましたがフルタイムではなかったため、CTO ではなく業務委託契約で参画しましたが、実際には CTO とほぼ相違ないと思える裁量を持って従事しました。)
単発的な様々な課題の解決に従事したため、以下に箇条書きで取り組みを記します。
・プロダクトの機能要件が未定義であるため、顧客と約束した期日までの残りの 2 ヶ月で実装することができるものでは、提示した課題解決を行えるプロダクトは完成し得ないだろうことを CEO に説明し、リリース期日を伸ばしました。
・プロダクトの要求を具体的に定義できていないため、解決したい課題の具体化と、それを解決するべきプロダクトの要求を考案するという、プロダクトオーナーとしての役割を CEO に依頼し推進しました。
・プロダクトの機能要件を具体的するために、プロダクトオーナーにヒアリングしトップダウン型でプロダクト要件定義を行うという、プロダクトマスターとしての役割を COO に依頼し推進しました。
・当初の実装タスクとして積まれている要件の抽象度が高く、開発者が具体的な実装タスクに落とす際に未定義仕様が多く生まれる状況であったため、アジャイルの手法を参考に、ストーリーと実装タスクの粒度定義を設けるよう提案し推進しました。
・上記リリースを以て資金調達をする前提のショート寸前のキャッシュフローであったため、ベータ版完成後の評価額を諦めてでもリリースまで資金を持たせるため、リリース期日を伸ばす前提で投資家に説明し、今すぐ調達に動くべきことを CEO に説得し、開発期間を確保しました。
・資金ショートの懸念や約束した期日が迫っている中で経営方針が不透明であったため、開発者のモチベーション維持のためのメンタリングや、メンバーに対して現状共有をするよう CEO に求める等、マネージメント領域に携わりました。
・開発着手時点で採用できた開発者 1 名のスキルセットがフロントエンドに寄っており、 RDBMS を含むバックエンドの開発にフルタイムでない自分が工数を割くことが現実的でないことを踏まえ、バックエンドに Hasura を採用する意思決定をしました。
・資金、市場両方の問題から採用人数を増やすことが難しいと判断し、開発者を少数精鋭に保つために要求水準の高い Job Description を定義する、ハイクラス求人媒体を使用するよう提言する、自身の繋がりから協力を得られる信頼できる人物を探し 2 名ジョインに成功するなどの採用考案を実施しました。
・開発フローが未整備であり、着手タスクの優先度や達成目標がないがタイムボックス(週次)とレビューのみ存在する状態で開発が運用されていたため、アジャイルにおける手法を参考とした見積もりや期日設定のルールを整備し推進しました。
・体験版提供前の品質確認体制ができておらず、バグトラッキングが機能していなかったため、バグトラッキングルールを定義し、新規実装タスクと平行してバグ修正タスクの優先度を整理するよう提案し推進しました。
・フルタイムの開発者では解決できないバグを調査し解決する等の技術的な助力も行いました。
・上記 QA 体制により、週次レビューでは開発が進んでいることの確認のみであり定量的に進捗を確認できるものではなかったことが判明したため、要求機能に対してどの程度完成しているか、現時点で期待すべき機能要件を満たすか、品質は低下していないか(デグレの確認等)、スケジュールに対してどの程度の進捗であるか、等を確認するよう提案し推進しました。
0 → 1 のフェーズで裁量を持って判断する経験から、経営という面では顧客や資金や目標評価額との折り合いをつけて判断することを、プロダクト開発という面ではプロジェクト全体の推進を、実装という面ではメンバーの力量や市場における採用見込みを踏まえた技術選定を、それぞれ知識ではなく経験にすることができ、また達成できたことに大きな喜びを感じました。
機械学習の推論結果を表示、検索するダッシュボードアプリケーションを開発運用するプロジェクト。
元々業務向けで最低限簡素であったフロントエンドを使いやすく刷新するために参画となったが、バックエンドのコードが経年劣化しており、フロントエンドの刷新には API から見直す必要があったため、全体アーキテクチャの再考から携わりました。
フロントエンドとバックエンドは OpenAPI ベースのスキーマを前提とし、実装としては Zod という TypeScript ライブラリを用いてモデル定義とバリデーションルールを定義する方針を採用しました。
特にスキーマについてはバックエンドとフロントエンドを同時に別のメンバーが開発することもある中で、共通となるデータモデルを前提として議論・提案することができ、想定通り効率的な開発・コミュニケーションを行うことができました。
今後サービスが増えることを予期し、マイクロサービスアーキテクチャを採用したいという案が当初あったが、チームの運用体力等も鑑み、アプリケーションサーバとしての ESC と機械学習に関連するサーバ郡、との分離を主とする案を提案し採用しました。
消費者向けの Web サービスを開発するプロジェクトに参画し、ほぼ純粋なフロントエンドエンジニアとしてアプリケーションの開発に携わりました。
自社開発初のサービス開発であったこともあり、再利用性の高いコンポーネントをデザインシステムとして定義し、実装には Stencil を採用して WebComponents として再利用可能性を高める取り組みをしました。
デザインシステムの実装であるコンポーネントをアプリケーション実装のライフサイクルと明確に分離することで、画面の変更が何の影響であるのか把握しやすくなり、意図しないデグレを防ぐ目的で有益でしたが、アプリケーション都合でコンポーネントを変更する必要がある場合にはその効能は得られず全体を確認しなければならないという点ではもっと工夫やルール定義、あるいはデザインフローの定義の余地を痛感しました。
実装面では、Stencil.js は採用例が少なく日本語の情報もほとんどないため、Stencil.js 自体ではなく CustomElements の仕様や議論、既存の Custom Elements 実装ライブラリのソースコードを参考にし、デザインシステムの実装として継続的にメンテナブル、かつインタラクションを含めアプリケーションから正しく責務を分離できることを意識して実装しました。
状態管理ライブラリに MobX を採用していたことからは設計上の新たな学びを得ることができ、特にフォームのバリデーションにおいては MobX が非常に有用であり、世論が固まっているように見えても、アプリケーションの規模や特性に応じて採用ライブラリを検討する余地は依然としてあり、意思決定において世論に任せつつあった気持ちを改める景気となりました。
ルーティングにおいては、ReactRouter の高い自由度からメンテナンス性が非常に低下したアプリケーションを多く見てきたこともあり、 Angular から着想を得た Outlet としてルーティング箇所を分割する設計を取り入れ、結果として Router 関連で致命的な困難に遭遇することなく開発をすすめることができました。
またバックエンドとの連携は OpenAPI をベースとして、メンバーが実装した自動生成を用いた型定義ライブラリを採用しており、 OpenAPI をルールではなく実装として活用できることの力強さを痛感し、これ以降 OpenAPI に強く感心を持つ景気となりました。
このプロジェクト詳細は公開されていません
Developer Success の一貫として開発運用環境を改善するプロジェクトに携わりました。
社内向けのプライベートライブラリはプライベートな git リポジトリを直接参照する構成となっており、ライブラリの依存関係は非明示的で、バージョン管理もされておらず、参照元リポジトリのデプロイ再現性がない状態だったため、明示的かつバージョン固定が可能で、メンテナンス性の高い構成へと一新する活動を行いました。
400 を超えるプライベートリポジトリに対し、運用中のアプリケーションの npm の依存ツリーデータを加工し依存を可視化する、依存の逆順にアップデート可能なバージョン管理とリリースフローを検討する、依存されていないように見えるリポジトリが本当に使用されていないか確認する等、 Node.js の専門的な知識を要する業務に携わり、これまで趣味として仕入れてきた細かい知識を実務で活かせることに非常に喜びを感じました。
全貌が見えてくるにつれて同時に片付けたい課題も増えてくるため完了までは当初よりも多くの時間を要しましたが、モノリポ化やリポジトリのマージ権限の整備と CI での自動デプロイによる権限統制・証跡の整備までも含めて完了しました。
このプロジェクト詳細は公開されていません
下記 IoT クライアントワークの傍ら、自社運営のクラウドサービスの PaaS (より厳密には所謂 iPaaS に相当する SaaS) 製品の開発・運用・保守に携わっていました。
まず 1 つは Web UI から設定した時刻ベースでイベントを発火する、マネージドな Cron のようなものを提供するプロダクトで、リリース後の運用フェーズから参加しました。
Node.js v4 系を動作環境として CoffeeScript で実装されており、 Web API と Job Worker が分離されていて Redis でキューイングするという構成は、Web サイト的なアプリケーションばかり勉強していた自分には非常に新鮮で、アプリケーション構成の知識が全く足りていないことを痛感する景気となりました。
インフラには IaaS を全面採用しており、プライベートネットワーク内で Redis Cluster を構築する、新規デプロイ時には Graceful Restart できるようにする等、運用を前提とした構築をはじめて目にし、大変勉強になりました。
ログはファイルベースのものを fluentd でバックアップする運用であったため、ユーザ問い合わせ対応でログを検索するために shell で awk や grep を駆使する術を学びました。また、ログを通じて格納されたデータを見ることから、コードベースへの理解を深める機会となることも経験しました。
長期運営するにあたりメンバーの入れ替えや人的冗長化を考える必要があるフェーズになった際には、 CoffeeScript を読み書きするメンバーが他にはいなかったため、幸いにもテストカバレッジが高かったことを担保に、 Decaffeinate (v1) を用いて 読み書きできる JavaScript へ変換しました。
この変換では Node.js v4 系では class field がサポートされていないがためにパッチワーク的な実装が出力されてしまいましたが、実行エンジンのアップデートは簡単ではないため、ビルドプロセスに TypeScript を導入し、現行のコードにも型を付けていく、という実装を提案しましたが、この提案はデプロイプロセスの変更のリスクを軽視していたため、採用には至りませんでした。
また静的解析により暗黙的な循環参照を発見したため修正しようとしたものの、 Node.js の require の挙動を理解するにつれ、影響範囲が膨大でとても手に追えないことが分かりました。
これらの経験から、開発当時の人数や納期、実装速度や当時のメンバーのスキルを踏まえ最適と思われる意思決定をしたにも関わらず、数年でメンテナンス性に影響が出てしまう、という事実を目の当たりにし、技術選定の大切さを意識しはじめることとなりました。
もう 1 つは、機械学習のモデルを API 経由で利用できるようにするプロダクトで、初期開発からベータリリースまで携わりました。
こちらも同様に Queue と Job Worker という構成を採用しており、フロントエンドを React 、 WebAPI と機械学習ワーカーを Python で実装しました。
機械学習の専門知識はどうしてもエンジニアの方が詳しいため、製品企画や競合調査等にも大きく関わりました。
私はもともと機械学習については簡単な知識しかなく、主に Web システムの開発の役割で参画していましたが、徐々に機械学習の基礎理論や適用範囲などを学び理解するにつれて、ドメイン知識を適切に分割したソフトウェアの開発でも、ドメイン知識の有無では設計や理解が全く異なるということを実感しました。
Docker Swarm や Consul を採用したマイクロサービス的なアーキテクチャ、mypy による静的検査、RAML を用いた API 仕様書とドキュメントを一言管理と、長期運用の視点で効率化を前提とすることができ、開発当初はコストを重く感じていたが、開発が後半になって恩恵も感じるようになったという経験からは非常に多くの学びがありました。
業務をIoT 化したい、IoT の新規事業を作りたい、という要望を持つ企業をクライアントに取り、アイデアデザインからプロトタイピング、 PoC の設計開発まで、ワンストップで行うサービスを提供するプロジェクトに開発者として参加しました。
主にプロトタイピング、PoC の開発フェーズに携わり、センサから取得した(前処理前の)ビッグデータの加工や可視化、その他 API 化しての活用等を行うアプリケーションの開発に携わりました。
データ可視化のフロントエンドを React と D3.js で、データを配信する API サーバを Node.js や Go (echo.go) で、大規模データの ELT プログラムを Go で、それぞれ開発し、 HTTP リクエストのデータよりもすでに格納されているデータに着目する案件に多く携わりました。
案件に使用するインフラは自社のニフティクラウドを使用しており、クラウドを前提としたインフラ設計や Ansible による IaaS の IaC 等、現代のクラウドにも通じる技術を活用して構築しました。
特に SPA でフロントエンドを実装することがまだ広く定着していない時代であったたえ、特に関心を持ち学んでいたことが幸いし、チームメンバーである同期に対してレビューや知識共有をし、チーム全体の能力向上に貢献できたと思います。
中でも ETL 案件では、 40 億を超えるレコード数のデータを PostgreSQL に格納する際 1 データずつ INSERT する都合もあり、実行速度や容量等を意識してテーブルとプログラムの設計を行う必要がある点で大きな学びを得ることができました。
また、テスト環境用データでの格納後のデータサイズ倍率を参考にして本番環境の構築見積もりを行ったため、インデックス生成の際のキャッシュが容量を圧迫すること、インデックスのサイズは格納元データ量に対し等差級数的に増加するわけではない、という点を見落としいたことを起因としてデータ格納バッチでエラーが発生してしまうという失敗をしました。
「推測するな計測せよ」という言葉を当時のリーダーから教わっていましたが、テストデータと本番データの差異の影響を「推測した」ことによって発生した問題であると反省し、より計測する意識を高める機会となりました。
また上記のようなバックエンドやバッチの開発に際し、 Go 言語を採用したことで、それまで動的型付け言語を主に書いていた自分にとって静的型付け言語の魅力を知る景気になったり、 SSH 先のサーバでセッション切断後もバッチ処理を継続するために screen に頼らずに Linux のプロセス管理や所有者を理解して正しく扱う知識を学んだり、実務的なエンジニアリングの知識を幅広く学ぶことができました。
前述するフロントエンドについての知識共有に関してもですが、自分がチームメンバーの同期から学ぶことも多く、今ある力の地盤となる経験だったと思います。