OBOEGAKI IN MY HEAD

主にIT関連の覚え書き

30歳でSIerのSEからスタートアップのソフトウェアエンジニアに転職して3年が経った

はじめに

忙しさにかまけて超久々の記事になってしまいました。

新卒で入社したSIerからWebサービスのスタートアップにソフトウェアエンジニアとして転職して3年が経過したのでやったことの振り返りをしようと思います。

自分と同じような境遇でWebサービス企業でエンジニアをやるかで悩んでいる方が仕事内容をイメージをするのに役立てればと思います。

転職前後の変化まとめ

3年経った結果

  • 入社時はバックエンド中心だったが、アプリ、フロントエンド、クラウドインフラ、チーム開発、運用などWebサービスを構築する業務について一通り経験できた
  • 新規サービスを立ち上げて継続的にリリースして運用するスキルと勘所が身についた
  • 少ないリソースで課題を解決することが求められる環境のため、開発の前に解決手段が正しいか議論したり、全体業務フローや将来を見越して取り入れるべき機能かどうかを検討する癖が身についた
  • サービスが成長するにつれ、どんなビジネス要求が現れるかを予測して設計に落とし込むべきか考えるようになった
  • Web系は未経験だったが、様々なプロジェクトを乗り越えたおかげで気づいたら技術リーダー的立ち位置になった

SIer時代

  • 数千人規模の会社で数十人規模の部に所属。扱うシステムは20年近く運用されてきたもの
  • 周りは業務委託のエンジニア含めGitHubすら知らない
  • 仕事は機能開発プロジェクトの要件定義(Excel)、設計(Excel)、テスト計画(Excel)、プロジェクト管理(Excel)など
  • リリースは数ヶ月に1度
  • ときどき開発もするが、開発マシンはWindows メモリ500MBでインターネット接続なし
  • 年収・福利厚生は良い。課長級で1000万、住宅補助フル活用なら30歳で600万半ばまで行く(自分は対象外だったけど...)
  • 労務管理はしっかりしている

Webサービス企業に転職するためにやったこと

  • 休日はだいたい自習室にこもって勉強・開発。平日も22時前に帰宅できたら自習室へ
  • VPSを借りて自作サービスをリリース
  • 自作サービスは他の人に譲渡してすぐに運用できるレベルを目指した。コードだけでなく、プロビジョニング(Vagrant、Ansible、Docker)、テストコード(単体テスト、E2Eテスト)なども準備
  • その他周辺ツール(エディタ、Gitなど)や設計などについて勉強
  • 勉強期間は1年半ほど

スタートアップ入社後

  • 入社当時は十数人ほど。エンジニアとしては5人目
  • 入社時に年収は100万以上下がったが、1年後の昇給で前職の年収を超える金額にはなった
  • リリースは1ヶ月に数回
  • 人が少ないのでいろいろやる。バックエンド、インフラ、アプリ、フロントエンド全部必要に応じてやる。顧客折衝も開発もサポートもやる
  • 入社当時はRailsの経験しかなかったが、都合よく人員がいるわけでもないのでフロント、アプリ、インフラも自分でやる
  • 開発マシンはMacBook Pro
  • 人員が少ないのでハードワークになりがち(最高月間残業時間 160h)
  • 大体自分でなんとかする必要がある
  • 勉強期間がかなり効いた。他のエンジニアとコミュニケーションを取るための前提知識が揃ったし、むしろその知識を活かして提案などができた。困ったのはAWS等のクラウド知識くらい。とはいえそこもVPSで色々構築したときの知識が理解に役立った
  • SIer時代の慣習もプロジェクトの確実性を上げるために役立ったりした。また、SIerのときにSQLを書きまくっていたおかげで開発・分析等で役立った
  • 鍵をもらって休日には自習室代わりにオフィスに行って勉強できた

転職1年目

toB向けSaaSのアプリデザイン刷新、ユーザ企業へのトライアル導入

転職後、開発開始したばかりのtoB向けSaaSの開発とユーザ企業へのトライアル導入の調整にアサインされました。

入社時点ですでにそのSaaSのネイティブアプリがあったものの、使い勝手が良くなかったのでデザインの刷新をしながら、同時にユーザ企業へトライアル導入することでフィードバックを得つつ開発をしていく、ということをしていました。

そのSaaSが利用される現場での業務内容を理解するためにユーザにヒアリングをしたり、現場に視察に行ったりとオフィスの外での作業も多くありました。 ヒアリング等で得た情報を整理して、現場での利用に適したアプリの画面フローをAdobe XDでプロトタイピングしてCEOと議論してフィードバックを得てプロトタイプを修正して...を繰り返してアプリをブラッシュアップしていきました。

現場に行ってアプリを使っているユーザの後を追いかけて使っている様子を観察したり、動画を撮らせてもらったり、ユーザ企業の事務所で作業させてもらっていたらコーヒーを淹れていただけたりとオフィス外での思い出が印象深いです。

このような現場目線での改善結果が評価され、このSaaSは後に大企業でのコンペを経て採用が決まりました。

外部コンサルを入れての技術導入

上記SaaSで数学的な問題を解決する必要があり、社内に適した人材もいなかったため、外部からコンサルを入れて取り組むことになりました。

コンサルの提案内容を理解し、効果のありそうなアプローチかを判断し、実装してもらい検収する...とすべきですが、このときは少しアプローチの精査が甘かったと反省しています。

最終的にコンサルから出てきたものは自分達でも実装できてしまうレベルであったため、外部の開発リソースを買うだけになってしまいました。提案内容に専門用語が出てこようと自分で中身を調べて理解しておくべきでした。

その後、現場からこの機能についての不満が出てきたため、改善を行うべく自分で調査していたら、この問題を解くライブラリがGoogleによってオープンソースで開発されていることがわかりました。

結局そのライブラリを使って自分で機能を作り直すことになってしまいました。結果としてコンサルが真にその分野の専門家ではなかったのだと思います。事前に自分で相談する予定の分野について調べておき、本当にその人がその分野の専門家であるかを見定めなければならないと認識した出来事でした。

とはいえ、このときの納品物は全くの無駄になったわけではなく、実は3年近く経った今でも一部使われていたりします。

新サービスA立ち上げ

toB向け新サービスを立ち上げすることが決まり、私はプロジェクト管理、要件定義、画面設計、開発を担当しました。これが初めてサービスの立ち上げから携わった初めてのプロジェクトでした。(この記事でやたらと新サービスが出てくるので新サービスAとします)

CEOの語るビジョンややりたいことをベースに議論しながら要件定義していき、どのような画面設計やフローにするかをプロトタイピングしつつ決めて開発する、というのは最初のプロジェクトとは変わらずです。

このときでは開発者が自分以外にももう2人いたのでタスク割り振りやスケジュール管理をしつつ運用していましたが、他のサービスの機能開発や運用をしながらだったので全然予定通りにいかず...。 結局ハードワークでなんとかするみたいな感じになっていました。 入社当時は1プロダクトのことだけしかやっていませんでしたが、このような新サービスが増えるたびに同時兼務が増えていきました。

このとき、実装する機能がどんな思想に基づいて実装されているかを明確にしたいという思いがあり、ドメイン駆動設計を勉強していたこともありプロジェクト憲章を作りました。この新サービスがどんなプロジェクトであり、どんな価値を提供するものなのかを文章にしてチーム内で合意を取りました。

プロジェクト憲章が機能検討時の判断の軸になることを期待しましたが、チーム内にあまり浸透させることができませんでした。定例会議の議事録の1行目にプロジェクト憲章へのリンクを貼っておいたり、短縮バージョンを貼っておいたりしたのですが、書いてあるだけでは見ないんですよね...。

プロジェクト憲章は残念ながらチームの役には立てませんでしたが、自分の役には立ちました。要件検討のときに、こんな機能をつけてはどうか、と提案があってそれの採用可否を決めるとき、その根拠がただの自分の感想ではなく、プロジェクト憲章で定義したこのサービスが提供しようとする価値に沿っているかどうかを根拠にしたことでメンバーの納得感が出ていたように思いました。

また、プロジェクト憲章を一番読んだ人間だったのでこのサービスがどんな価値を提供すべく立ち上げられ、どんな性質を持つべきなのかについて一番語れる人物になっていました。後に立ち上がる新サービスBでもプロジェクト憲章に近い文書を作って展開したら途中参加のエンジニア達に喜ばれました。そしてSlackのチャンネルにピン留めしてくれたのですが、やっぱり見てもらえず...。なんでこのプロジェクト始まったんですか?と聞かれてチャンネルのピン留めを紹介する、という感じでした。

1年目で使った技術・得た知識など

  • Railsでの開発(業務としては初)
  • AndroidJava)アプリの開発
  • Vue.jsでの開発
  • R言語での開発(コンサルの納品物を修正するために)
  • Pythonでの開発(コンサルの納品物を自分で再実装)
  • AWSでのインフラ構築(ElasticBeanstalk、EC2、S3、CloudFront)
  • LP制作(HTML+CSS+Googleフォーム+JavaScript
  • プロトタイピング(Adobe XD)
  • 新サービス立ち上げ時に必要なタスク(ロゴ制作、PR方法検討、LP制作、競合からの調査防止などを踏まえたサインアップ導線整備など)

2年目

新サービストライアル導入

前年に作った新サービスAをユーザ企業でトライアル導入しました。企業間を連携するための機能があり、3社もあったので調整が大変でしたが、どんな検証をするのか、どんな現場オペレーションにするかを整理してなんとか実現しました。

そしていつものように現場に張り付きオペレーションを観察したり、ヒアリングをしたりしました。 連携機能を使わない企業ではうまくサービスが使われたものの、企業間連携は業種が異なるため、A社にはメリットがあるもののB社のメリットが薄いということになり、トライアル以降は進展することはありませんでした。

Android用チャットライブラリ実装

新サービスAでAndroidアプリとブラウザ間でチャット機能を実装することが決まりました。

アプリにそのまま組み込むこともできたのですが、アプリとブラウザ間のコミュニケーションというのは社内のプロダクト全てに共通して必要とされる機能であると考えたため、ライブラリとして他のプロダクトにも組み込めるような形にして開発しました。

チャットのバックエンドは外部サービス任せにしてSDKを使って実装したものの、他のプロダクトに組み込めるような形にするのが大変でした。このライブラリは後の新サービスBに実際に利用されました。また、他のプロダクトでもチャット実装の要望が出てきたときに工数節約が期待されました(結局チャット実装そのものが見送られてしまいましたが)。

新サービスB立ち上げ

新サービスAは残念ながらクローズすることが決まりましたが、toB向けの新サービスBが立ち上がることが決まりました。私はいつもどおりプロジェクト管理、要件定義、画面設計、開発を担当しました。

ある事業領域における一通りの業務を機能として実装する必要があったため、まずはその事業領域における知識をつけるために業界団体が公開している資料を読み漁りました。また、その事業領域の現場視察の機会に現場の方に質問しまくり、写真撮影させてもらい、とにかく情報収集しました。

それらの情報を元に要件定義・画面の情報設計をしていきました。かなり複雑な要件になることが容易に想像できたため、テーブル設計も入念に行いました。その甲斐あって現在に至っても大きな問題なく機能拡張し続けられています。

また、当時社内では残念ながらテストがあまり書かれていませんでしたが、このプロジェクトではテストがないと絶対に破綻すると感じていたので、少なくとも全エンドポイントのリクエストテストは書く、ということを実践しました。

バックエンドはほぼ自分が書いていたのでテストを書くことは実践しやすかったですが、後に他のメンバーが加わったとき自然とテストが書かれるようになったのが印象的でした。すでにテストが整ってるとテストデータの用意が簡単なために書くハードルが下がったり、自分が整ってるものを乱すわけにはいかないみたいな心理が働いたのかもしれません。

このプロジェクトで業務領域の知識を元にテーブル設計したり、テストの整備などを頑張った甲斐もあって設計のスキルが向上したように思います。また、ユーザ企業にトライアルで使ってもらいる間にも絶えず機能拡張を続けていたため、バックエンド、フロントエンド、アプリ間のバージョン互換性にも敏感になりました。バージョンの組み合わせで問題が発生しないように互換性を保つように開発し、リリースの順番にも気をつけるようになりました。

ドキュメント整備

人が増えてきたこともあって、都度システム構成や業務知識を説明するのが大変になってきました。そろそろドキュメントを整備しないといけない、ということでドメイン駆動設計のコンテキストマップを参考に社内にどんなシステムがあってそれぞれがどんな業務領域をカバーしているかを表す図を作成してチームに展開しました。

リリース手順の自動化が甘いところは、一時しのぎですが手順のチェックリストを作ってミスを防ぐようにしました。その他にも機能追加をするときに見落としがちな影響箇所などを漏れなく確認できるようなチェックリストも作って属人性を排除するよう務めました。機能が多かったので要件定義時などに影響箇所のチェックとしてこのリストはとても役立ちました。

2年目で使った技術・得た知識など 

  • Railsでの開発
  • Vue.jsでの開発
  • Pythonでの開発
  • AWSでのインフラ構築(ElasticBeanstalk、EC2、S3、CloudFront、DynamoDB、Lambda)
  • プロトタイピング(Figma
  • ドキュメント整備(esa、draw.io、Plant UML
  • 互換性を保って継続リリースする方法
  • わからない業務領域でも業界団体が資料を公開してるので調べられる

3年目

新サービスBのユーザアカウントモデルのリファクタリング

ビジネス要求により新サービスBのユーザアカウントの考え方が変わりました。今までは業務1をやる人のためのアカウント、業務2をやる人のためのアカウントという考え方でしたが、アカウントを作ったらやる業務に応じて権限を変えることで業務1, 2の両方をできるようにすることになりました。

もともとユーザアカウントと権限という分け方をしていれば良かったですが、権限が違えばやることが全く違ってくるので業務1ユーザモデル、業務2ユーザモデルのように別々のモデルとして作っていました。そのため、統合されたユーザモデルを作り、それらに権限をつけ外しできるようにし、さらに権限に応じた機能制限を入れる必要が出てきました。

テストが無かったらその場しのぎで負債を残すところでしたが、幸い全エンドポイントにテストを書くことは継続されており、ちゃんとした設計へのリファクタリングをすることができました。やっぱりテスト大事。

新サービスCの立ち上げ

新型コロナウイルスの影響で緊急事態宣言が出されることが濃厚になった頃、この状況下で社会のために我々ができることをやろう、ということでtoC向けサービスを立ち上げることが決まりました。

緊急事態宣言内でのリリースを目標に最悪でも1ヶ月後にバックエンド、AndroidiOSアプリを用意しなければならず、さらには決済機能も実装しなければならないということでかつてないほどの短納期プロジェクトとなりました。

要件定義は企画チームが行い、私はバックエンドの設計、実装、さらにFlutterによるアプリ実装にも加わりました。
さすがにテストを書く暇がなかったものの、決済に関しては問題を起こすわけには行かなかったのでそこだけはテストを書いて後はとにかく実装に時間を割きました。これだけでもだいぶ役に立ちました。他のところは要件が変わったりしていたのでテストを書かずに正解だったかもしれません。

アプリ開発AndroidiOSアプリを個別に作るのは不可能と判断し、経験者がほとんどいないもののFlutterで開発することにしました。最後の方はエンジニア総出でFlutterを書いていました。
開発中の30日の間で休んだのは1日だけ、朝の4時まで開発、その5時間後に勤務開始して26時まで開発、みたいなだいぶぶっ飛んだ働き方もしつつ、4月の最終週にはなんとかリリースにこぎ着けました。

急ごしらえなので保守を心配しつつも、ゴールデンウィークはゆっくりできるかと思いきや、一本の電話により次のプロジェクトの始まりが告げられます...

新サービスCにtoB向け機能追加

新サービスCはtoC向けですが、そのユーザと接点をもつことができるようなtoB向け機能を追加することが決まりました。

緊急事態宣言下で業績の下がる小規模企業に向けた機能で、ある自治体との連携の予定が取れたということでその自治体の記者会見までに用意する必要があるため、これまた短納期でのプロジェクトとなりました。

私はtoB向けのサインアップ機能や出店機能、出店企業を検索するためにElasticsearchによる全文検索、緯度経度検索などを実装しました。toB向けiOSアプリ、Androidアプリも用意してゴールデンウィーク返上で実装し、リリースしました。

しかし、記者会見ではベンチャーと連携していくみたいなことを言ったものの、具体的な名前を出してもらえず肩透かしをくらったのでした。

新サービスCの料金計算方法を変更&キャンペーン機能追加

新サービスCの利用を促すために料金割引キャンペーンを実装することになりました(これまた短納期で)。さらに同時に料金の計算方法を全く異なるものに変えるというものです。このときも要件定義は企画チームに任せ、開発に全振りしました。

アプリの画面上に料金を出しているところが何ヶ所もあり、アプリ内を回遊しているユーザに影響を出すことなく料金の計算方法そのものを変えたり、キャンペーンを適用して旧アプリの動作に影響を与えず価格を変更できるようにするのは工数がかかりすぎるため、ユーザ告知をしてメンテナンス時間を入れました。

結果的にはメンテナンスを入れたものの、要件が確定するのを待っていたら開発が間に合わないので、メンテナンス無しでリリースすることも考え互換性のある形で開発していました。そのお陰で新バージョンのアプリがなくてもバックエンド実装を進めることができましたし、メンテナンスが必要になる場合の影響調査も進みました。

料金計算方法変更およびキャンペーン機能は無事リリースされ、短納期だったにも関わらず料金関係の問題も起こさずに済みました。

機能統合プロジェクト

いくつかの新サービスが立ち上がる中で、短納期のために同じユーザに向けた機能が別々のサービスに実装されており、その機能の改修に他のチームと連携を取る必要があったり、それぞれのサービスでデザインが異なっていたりと開発をする上で課題があったのでその機能を片方のサービスに統合することになりました。

統合するにあたっては、一番最初に統合後のデータ構造を設計してチーム内でレビューを受けておき、バックエンドとフロントエンドの開発者が同じデータ構造のイメージを共有しながら作業を進められるようにしました。今後も統合が必要と思われる機能は、以前コンテキストマップを作成したときにあたりがついていたので、将来の統合も踏まえて設計していきました。

しかし、一方のシステムの設計が非常にわかりにくく、さらには特殊なユーザアカウントにだけ発動するロジックなどがあり、その分析に時間がかかりました。その分析結果のドキュメントが膨大になってしまい、それを理解して何に気をつけて実装すればいいかを知っているのは自分だけみたいな状態になってしまいました。

そして不運なことに途中で私は他のプロジェクトを手伝いに行く必要が生じました。とはいえ、ドキュメントを書きつつタスクチケットへのリンクも都度行っていたので、引き継ぎ後に来る質問も大体はこのドキュメント見てください、と軽い説明で済みました。とは言え量がすごいので説明コストがかなりかかりました。

このプロジェクトは現在も継続中です。

3年目で使った技術・得た知識など

  • Railsでの開発
  • Vue.jsでの開発
  • Flutterでの開発
  • AWSでのインフラ構築(ElasticBeanstalk、EC2、S3、CloudFront、Elasticsearch Service)
  • ドキュメント整備(esa、draw.io、Plant UML
  • 決済系システムの知識

おわりに

3年分を一気に振り返ったため激長文章になってしまいました。ここまで読んでくださった方は本当にありがとうございます。

SIerからスタートアップに転職してからあっという間の3年でしたが、率直に言って転職して良かったです。SIerにいた頃は周囲は技術に興味がなかったのでシステムの設計は凄惨たる有様でしたし、Excelにテスト結果のスクリーンショットを貼り付けて印刷してファイルに閉じる、などの誰が喜ぶのかわからないしょうもない書類作成作業などとてもつらい時間が長かったです。

転職後はどうやったらユーザの課題を解決できるかを考えてみんなで議論したり、より良い設計を考えつつ実装したりとプロダクトのためになる行動が求められます。スピード感も全く違って1週間先すら読めないみたいなことがあって非常に濃い3年間であったと思います。

転職直後は、まずはWeb系のソフトウェアエンジニアとして1人前になることを目指していましたが、この3年間で様々なプロジェクトを乗り越え一通りの業務を経験したことで、とりあえずその目標は達成できたかなと思います。

スピードが求められ、設計に十分な時間が取れなかったりリリース時期は変わらないのに要件は変わったりとハードワークせざるを得ない場面も多数あり、健康に支障をきたすときもありました(1回目の緊急事態宣言下の超ハードワークにより腕を故障し、今でも影響が残っています)ので、良い事ばかりではないですが、これからは健康にも気をつけて引き続き頑張っていこうと思います。