@kyanny's blog

My thoughts, my life. Views/opinions are my own.

取引先とのシステム連携の開発タスクにアサインされた。 Production 環境の API にアクセスするためには審査が必要で、ビデオ会議中にアプリケーションを実行してテスト環境の API を呼び出すデモをしろという。先方のエンジニアによるアクセスログの確認も審査項目に含まれているのだ。

会議依頼の参加者名簿に外国人っぽい名前があったので予感はしていた。案の定、会議が始まるやいなや先方の営業担当者から「英語で良いですか?」と。まさかこの職場で英語ミーティングをすることになるとは。久しぶりの英会話だったのでたどたどしく、発音も悪く、相手の込み入った質問は理解できず営業担当者に通訳を頼むなど散々だったが、突然の英語ミーティングにも動じずに応じられるだけの自信を失っていなかったのはよかった。

締め切りまでの開発期間は一ヶ月あるという話の案件だったが、本番系 API の利用開始までは審査通過後最大二週間を要するということがわかり、途端にスケジュールが厳しくなった。審査時にデモが必要なことと合わせると、二週間でほぼ全ての開発作業を終える必要がある。デモに足るアプリケーションの開発が済んでいなければ審査日を後ろ倒しせざるを得ず、 API の利用許可がおりる日もそのぶんずれ込む。この事実を認識したときは青ざめたが、最大のマイルストーンである審査を無事に乗り越えられてほっとした。

誰も褒めてはくれないだろうし賞賛を期待する筋合いの話ではないが、実質残り二週間、祝日があったのでわずか8営業日で開発し終えなければならないと判明した時点で、不慣れな Go ではなく慣れている Ruby で審査を通すための実装を書く、という方針を思いついたのは我ながら好判断だったと思う。

自社サービスのバックエンドシステムは Go で書かれており、今回開発する新機能も当然そのアプリケーションに組み込むので、 production 環境にリリースするためには Go で書く必要がある。しかし、不慣れな言語でいきなり清書するのは不確定要素が多く、間に合わないリスクが高い。

審査時に実行するデモはあくまで API 呼び出しログの確認が目的であり、何言語で実装されていようが、書き捨てのコードであろうが先方は気にしない。そこに着目し、「審査を通すための実装を二週間で書くこと」と「 production リリースのための Go 実装を一ヶ月後までに書くこと」に課題を分離したことで、一つ目の課題を解決するためのより良い手段(書き慣れている言語を使う)を採用できた。

先週の月曜に「あと二週間でやらないといけない」と気づき、一日中焦っていたが寝る前に「Ruby で書けば間に合うかも」というアイデアを思いつき、火曜から実装を開始して金曜の夜には6割程度実装できていた。データベースのテーブル定義など、抽象度の高い設計は頭で考えるだけではなかなかまとまらず、手とコードを動かしながら煮詰めていくアプローチが功を奏した。

一週目で終わらせて二週目は調整や審査書類の準備などに充てるつもりだったが、結局二週目も丸々使ってビデオ会議の数時間前までコードをいじっていた。 Ruby コードを書く際の手詰まりやロスは少なくてこれだから、もし最初から Go で書き始めていたら今頃大変なことになっていただろう。 Ruby に習熟していて本当によかった。習熟度合いが同程度ならプログラミング言語による差はあまりないとは思うが。

難関をクリアしたとはいえ、次は Ruby で実装した処理を Go に移植するタスクが待っている。アドバンテージは無いし、機能を追加する既存アプリケーションの仕様も紐解き理解しながらの作業になるので、依然としてスケジュールは厳しい。しかしここでも「慣れてる言語で一度書く」の恩恵は得られる。

外部システムが提供する API はビジネス用途なのでかなり多機能で、エンドポイント数は多いしレスポンスのデータモデルも複雑だ。先方のシステムは当然 Web UI もあり、オペレーターが見ている UI 上の情報は API レスポンスのどれか、などの知識も地道に調査して獲得しなければならない。それらを理解した上でようやく、要求仕様を満たすビジネスロジックを実装できる。

自社システムと他社システム両方の仕様に疎い状態で両方を調べながら、さらに不慣れな言語で新たなビジネスロジックを実装するのでは四重苦だが、 Ruby でデモ用アプリケーションを書く過程で他社システムの仕様理解は進み、実装すべきビジネスロジックやデータベース設計も固まった。四つの課題のうち二つは解決済みで、残る二つに注力すれば良い。これならなんとかなるかも、という気になれる。

さらに奥の手として、自分の実装パフォーマンスが出なかった場合に応援を頼む可能性は低くない。その場合、作業分担のやり方がまずいと増援を効果的に使えない。仕様に明るく実装が遅い開発者と仕様を知らず実装が速い開発者のチームならば、仕様に明るい人がプロダクトマネージャー的に振る舞って実装が速い人の手が止まらないようにするのが効果的だろうが、コミュニケーションによるロスは無視できない。

開発者同士であればコードで会話する方が効率が良い。すでに実装済みのビジネスロジックを別言語に翻訳することは、参照先言語に対する習熟度にもよるが、文書や口頭で伝えられた仕様からビジネスロジックを考えて実装するのに比べてずっと単純な作業であるはずで、より速く実装できるはず…というようなことも考えながら、 Ruby で「どうせあとで捨てる実装」を、 Go プログラマが読みやすく、 Go に翻訳しやすいように、あまり「Ruby っぽさ」を活かしすぎないように意識しながら書いた。

これが功を奏するかどうかは未知数だが(他人に頼らず自分一人でスケジュールを守れる速度で実装できるに越したことはないので)、保険としては悪くない手だと思うし、そもそも自分が Go で書き直す際も参照実装として大いに参考になるはずなので、一粒で何度もおいしい、コストパフォーマンスに優れたアプローチだったのではないかと思う。

以下のような、システム開発における持論とも合致する。

  • 書いたコードを捨てることを嫌うのは間違い
  • システム開発が難しいのは、基本的に「まだ世の中に無いものを作る」から
  • 同じプログラムを二回書いたら二回目の方が速く、上手に書けるはず

このへんの考えは過去にも書いたことがある気がするが、改めて整理したいとも思う。