こんにちは! 2023年新卒エンジニアの伴野・谷・和渕です。
サイボウズでは、2023年エンジニア新人研修の集大成として、チームに分かれてソフトウェア開発を行う実践演習が行われました。この記事では、各チームがどんな成果物を作成したのかを、チームごとにご紹介したいと思います。
エンジニア新人研修全体については以下の記事で詳しく紹介されています。ぜひそちらもご覧ください。
概要
実践演習では3チーム(「チーム gogo!」・「明日から」・「TEMBIN」)に分かれ、それぞれ一つのソフトウェアを2週間で開発しました。「サイボウズ流チーム開発を新メンバーだけで実践できた」「未知見の課題に対してどう行動すればよいか考えるきっかけになった」というコンセプトのもと、自由な発想で取り組みました。
チーム gogo!
チーム gogo! では、演習開始時に Mastodon や Misskey などの分散型 SNS が話題になっていたことにヒントを得て、Bozudon(ボウズドン)という名前の分散型 SNS サービスを Next.js 13 と Rust を用いて開発しました。2 週間という短い開発期間でしたが、ポスト・リポスト・いいね・リプライ・フォロー・画像の投稿と表示などの基本的な機能を実装できました。
さらに Bozudon では、Mastodon や Misskey などがサポートしている ActivityPub*1 というプロトコルを実装しました。その結果、Bozudon のアカウントからMastodon のアカウントをフォローして投稿を見たり、逆に、Bozudon での投稿を Mastodon から確認できるようになりました。
Bozudon のソースコードは MIT ライセンスのもと GitHub 上で公開しています。
開発は、フロントエンドチーム(2 人)とバックエンドチーム(3 人)に分かれて行いました。演習期間中、リモートワークをするメンバーも多かったのですが、適宜 Zoom を繋いだりチャットをしたりして、わいわいコミュニケーションをとりながら開発を進めることができました。
開発を始めるにあたって、フロントエンドとバックエンドは双方とも、Mastodon の REST API を実装することにしました。というのも、Mastodon の REST API には詳細なドキュメントが存在するため、これによってフロントエンドチームとバックエンドチームで API について共通認識を得ることができると考えたからです。実際、この方針によってコミュニケーションコストが削減できたほか、フロントエンドとバックエンドの結合を行った際も、スムーズに作業を進めることができました。
フロントエンド
フロントエンドの開発は、Figma を使ってデザインカンプを作成するところから始め、その後、コンポーネントやページごとに Next.js 13 による実装を個人作業で進めました。先にデザインカンプを作成することで、実際にコードを書く段階になってから、作るものに対する認識をチームメンバー間で統一できました。また Figma の Developer Mode を使うことで、Figma 上で見えている状態をそのまま実装しやすくなりました。
実装のテストでは、社内ネットワークに立てた開発用の Mastodon サーバを利用しました。これによってバックエンドの実装が間に合っていない機能もフロントエンド側で実装・テストでき、作業を効率化できました。また、Mastodon の API はクライアント側に ActivityPub の存在を意識させない作りになっているため、仕様に従って実装するだけで Bozudon と Mastodon との連携ができるという奇妙な体験ができました。
バックエンド
Bozudon のバックエンドは Rust で実装をしました。3 人のチームメンバーのうち Rust に馴染みがあるのは 1 人だけだったので、開発の初期段階ではその人が中心となって環境の整備やフレームワークの導入などのタスクを行い、あとの 2 人がキャッチアップするという流れで開発を行いました。途中からは他の 2 人も Rust に慣れてきたため、実装する REST API のエンドポイントごとに並行して個人作業で実装を行いました。
開発中、ORM として採用した SeaORM で 1 対多や多対多の関連を扱う仕組みを理解するのに苦労しました。Mastodon の REST API のレスポンスでは色々なテーブルからデータをかき集め JOIN して返す必要があります。しかし、Mastodon が実装されている Rails(ActiveRecord)では簡単に書ける処理も、SeaORM では煩雑になることが多々ありました。また、リプライツリーなどの再帰的なクエリは SeaORM では扱えないように見えたので、仕方なく生の SQL クエリ(WITH RECURSIVE ...
)を書くことで対応しました。
チーム 明日から
チーム 「明日から」 はタスク管理アプリと紐付られるポモドーロタイマー EVERyGREEN を開発しました。
(※ ポモドーロタイマーとは、25分の集中と5分の休憩を繰り返すことで作業の生産性を高める「ポモドーロテクニック」を行うためのタイマーです。)
EVERyGREENは、チーム内のタスク管理にこだわりのあるメンバーが抱えていた、個人作業において「タスクとそのタスクにかかった時間を簡単に紐付けて作業状況を振り返りたい」、 「自分が作業をどれだけ頑張ったかを一目で見たい」という課題を解決するための Web アプリケーションです。ポモドーロタイマー機能を使うことでタスクとそのタスクにかかった時間を簡単に紐づけることができ、ポモドーロタイマーを回した回数が可視化できるグラフ機能を使うことで自分の作業の頑張りを一目で確認することができるようになっています。
外部のタスク管理アプリと繋ぐ部分を自作しやすいような、エンジニアフレンドリーな設計にすることで、普段使っているタスク管理アプリから離れることなく時間計測機能を追加できるように工夫しました。
チーム明日から では、成果物以外にも開発のプロセスを大切にしながら研修を進めていったため、以降は開発プロセスをメインに説明します。
私たちのチームでは、以下の目標を掲げて開発を行いました。
- 研修の最後だからこそ、全員で仲良く楽しく完走する
- やりたいこと・チャレンジしたいことを気軽に口に出す & 積極的に取り組む
- 成果物は何らかの形にすることを目指す
- 領域を超えてお互いに学び合う
目標の設定に際して、私たちのチームは唯一デザイナーがいるチームだったので、デザイナー、ソフトウェアエンジニア、QAエンジニアの3つの視点の違いを共有しながら開発を進めることができるようにと、この目標を設定しました。
お互いやりたいことを気軽に口に出すという目標の通り、自分の役割を果たしつつ積極的にやりたいことをやってみよう!という雰囲気で開発を進めることができました。例えば、QAのメンバーがソフトウェアエンジニアとモブプログラミングを通して製品コードを書いたり、デザイナーのメンバーがユーザのペルソナ作成やユーザーストーリーといった初期の段階をリードしたりしました。これによって領域を超えてお互いに学び合うという目標も達成されました。
このように当初掲げた目標の通り開発が進められたのは、以下の要因が大きかったと考えています。
- 目標を決める段階でお互いの認識を合わせるまで議論できた
- 技術全振りではなく、今後サイボウズで働くにあたって役割の違うメンバーがどう協調するかを意識しつつ楽しく進めるという認識を合わせた
- チームで作業内容を共有する機会を定期的に取った
- 朝会で「体調どうですか?よく眠れましたか?」とメンバーの調子を確認した
- 進捗共有を行うことで、チームとしての全体的な優先度を確認しながら開発を進めた
一方で、全てうまく行ったわけではなく、以下の点はこれから配属後働く中で意識していきたいと思いました。
- デザイナーとエンジニアの同期
- エンジニアに対してデザイナーがFigmaで作成したデザインをどう共有するかで苦労しました。同期する機会を設けることで解決しましたが、実際働いていく中でどのように繋ぎ込みを行ったら良いか模索していきたいです。
- 開発する際の引き出しの多さ
- タイマー周りの状態遷移が複雑で、かなり苦労しました。複雑な要件に対する引き出しを増やしていきたいです。
現在チームで製作した成果物はOSS化してタスク管理にこだわりのあるメンバーのために開発を継続できる形にするよう手続きを行なっています!
チーム TEMBIN
チーム TEMBIN はテキストチャットツールの作成を行いました。 チャットツールにはWebアプリケーションの基本となる様々な要素が含まれており、実装すべき機能の幅が広く、自分たちで作ることによって学習になると考え、選びました。
技術選定
チーム TEMBIN はフロントエンド・バックエンド・インフラ・QA/PM/SM の領域でメンバーを分けて、それぞれの領域で使用技術や進め方を決めました。
どの領域でも共通して「やってみたいことに挑戦・使ってみたい技術に挑戦」をコンセプトに進めていきました。
フロントエンド
チームの技術選定の方針に従い、以下の技術を使用しました。
- フレームワーク:Next.js
- Next.js 13から登場したApp Routerで開発しました。この選定はメンバーの技術的関心によるものであり、開発のモチベーション向上に貢献しました。また非同期処理をコンポーネントに直接記述できる、バンドルサイズを削減できるなどのメリットもあるため採用しました。
- CSS:daisy UI
- daisy UIはTailwind CSSをベースとしたUIライブラリです。UI実装の柔軟性と開発コストのバランスの良さを考慮し、daisy UIを採用しました。
- 状態管理:jotai
- jotaiはReact 用の軽量な状態管理ライブラリで、同じ状態管理ライブラリであるRecoilとほとんど同じ要領で扱うことができます。今回の開発では大規模な状態管理が不要だったため、扱いやすいjotaiを採用しました。
初めて使用する技術ばかりだったので、使い慣れた技術を使用する時と比較して、開発速度自体は落ちてしまいました。しかし研修を通じて様々な技術に触れることができたので、学習の観点では有意義な機会となりました。
バックエンド
使用技術としては、サイボウズの Neco 基盤開発にも用いられている Go 言語を選定しました。また Web サービスの動作原理を学習する狙いもあり、リッチなフレームワークは使用せず、なるべく自前で機能を実装してみることにしました。
今回実装する上で特に工夫したのは、以下の2点です:
- Cookie と KVS を用いたセッション管理
- セッション ID を key、ユーザ名を value としてKVSに保存し、セッション ID は Secure で HttpOnly で SameSite=Lax な Cookie に保存しました。このようにサーバーサイドでセッションを保持することにより、ログアウトを可能にしました。
- リアルタイムで新規メッセージを取得するロジック
- フロントエンドからバックエンドへ polling を行う際に、最終アクセス時刻を Cookie で保持させました。そしてサーバー側では、サーバー側の処理が重くなった場合も取得忘れが発生しないように、最終アクセス時刻 - 10 秒 の時刻より作成時刻が新しいメッセージを DB に問い合わせました(それ以上サーバー側が遅延した場合を考慮出来ていないため、このロジックは今後改善していきたいです)。
可能な限り自前実装するという方針の下では、開発速度が少し遅くなってしまうこともありました。しかし普段当たり前のように使用している機能の詳細に考えを巡らせることが出来たため、研修として有意義な機会となりました。
インフラ
高可用性なインフラ基盤の作り方を学習することを目標に、Kubernetesクラスターを構築しアプリケーションのデプロイ環境にしました。
3ノードのKubernetesクラスタ(1×master, 2×worker) + ロードバランサ1台で構築しました。
簡単な構成図は以下のようになっています。
ノードのOSにはコンテナワークロードに最適化されたLinuxディストリビューションであるFlatcar Container Linuxを用いました。Kubernetesのディストリビューションはkubeadmを用い、Ignitionでセットアップをすることで、マシンを起動すると自動的にKubernetesクラスタのノードとして参加するようにしました。
また、Kubernetes上にMySQLをデプロイするため、MOCOというMySQLオペレーターを使用しました。さらに、MySQLで使用するストレージを提供するため、TopoLVMというCSIプラグインを使用しました。
これらのソフトウェアはサイボウズがOSSとして開発しているものです。
MOCOやTopoLVMの詳細についてはこちらをご覧下さい
また、各種コンポーネントや開発したアプリケーションのデプロイはArgoCDを用いて自動化を行いました。ArgoCDを用いることで、GitHub上に置いたmanifestを更新するだけでデプロイが可能となり、作業時間の短縮に役立ちました。
研修で作成したアプリケーションをデプロイするための環境としてはかなり大掛かりなものになってしまいましたが、0からKubernetesクラスタを構築することで各種コンポーネントの設定やKubernetesでのストレージの扱いへの理解を深めることができ、とてもいい経験になりました。
QAエンジニア / スクラムマスター / プロダクトマネージャー
QAエンジニアとスクラムマスター(以降 SM)とプロダクトマネージャー(以降PM)を兼務し、プロダクト・プロジェクトをより良いものにすることに挑戦しました。
PMとSMを兼務することは、あまり良いものではないと言われています。しかし、チームとして開発を進めていく上で必要な役割であり、チームの人数を鑑みた上で、兼務に挑戦するという判断をしました。 実際兼務をしてみると、自分の中で、PMとしての側面とSMとしての側面での考えが衝突しました。結局1個人の中で落とし所を見つける必要があり、その判断に対して自信が持てないという難しさを感じました。結論としては、やはり役割を担う人は別の人が良いと感じています。すでに言われていたことではありますが、自身の体験として実感できたのは非常によかったです。
QAエンジニアとしては、主に機能仕様書からどんなテスト項目が発生しうるかを想像し、テスト項目書の作成と実施を行いました。その際に利用者の視点に立ち、その機能は分かりやすいか?想定外の使用方法はないか?を意識して考えました。 試験の実施に関しては、テスト項目書の内容に加えて、SQLインジェクションが発生しないかどうか、約90通りのパターンをBurpSuiteというツールを用いて検証しました。
2週間、QAエンジニアとしてプロダクト開発をしてみて、機能仕様書だけで試験項目を作成するのは非常に難しいと感じました。また、モックを用意することができていれば、よりスムーズに進めることができたと感じています。
*1:ActivityPub の仕組みについては、Mastodon の公式動画が参考になります。英語音声ですが、日本語字幕があります。