← as/engineer
2026-03-15 – 2026-06-22
42TokyoC++Team

WebServ

WebServ 振り返り

tkisaku/webserv — C++98で実装したHTTP/1.0サーバー。42Tokyoカリキュラムの一環として、ikawamuk・kokuritaとのチーム「プロトコル飲酒.com」で開発。

開発計画とその結果

開発期間は2ヶ月(3/15〜5/31を予定)とし、ウォーターフォール型で進めることにした。前半1ヶ月をデザイン期間、後半1ヶ月を実装期間とする計画。役割も最初に決めていた:

  • ikawamuk: コードの質を追求する人
  • kokurita: PM(締切を管理する人)
  • tkisaku(自分): 最終的な判断をする人
日程 内容
3/15 準備期間開始
〜4/1 準備期間
4/1〜4/8 開発要素・全体設計の検討
4/12 最終決定・発表会
4/15 全体設計すり合わせ
5/1〜5/15 実装(分担・詳細設計・テスト)
5/15 最初の提出
5/31 完全終了

実際の結果: 最終的な完了は6/22。当初予定から約3週間延びた。

最初の躓きは設計フェーズの入り口で起きた。各自が個別に勉強してデザイン案を持ち寄り、優れたものを採用する計画だったが、実際にデザインを進めたのは自分だけだった。そのため、自分が作った設計をたたき台にして4月頭からチーム全体での検討を始める形になった。結果的に5月に入る前にはデザインフェーズを終えられた。

実装フェーズでの当初の役割分担:

  • ikawamuk: poll()やacceptなど、Connection管理・全体の構造を決める部分
  • kokurita: HTTPRequestから情報を読み取り、処理を実行してHTTPResponseを作る部分
  • tkisaku(自分): Requestの逐次パーサーを実装し、Requestクラスに値を入れて次の処理に渡す部分

実装が進む中で、kokuritaの作業量が当初の見積もりより少ないことが分かり、最後の3週間でタスクの再分配を行った。最終的な担当は:

  • ikawamuk: 静的ファイルの読み込みとResponseクラスへの格納(正常系・4xxなどのエラーページ含む)
  • tkisaku(自分): ファイルのアップロードと削除、TempFileクラスの実装など
  • kokurita: HTTPResponseBuilderの全体構造の決定・監修、CGI部分の実装

git fameの結果でも、最終的な行数・コミット数は自分が最も多く、設計のたたき台作りから実装の中核まで広く関わったことが裏付けられている。

役割分担の機能面とは別に、自分はチームの基盤整備も多く引き受けた。clang-formatclang-tidyの導入、GTestの導入、Markdownでのドキュメント整備など、機能実装そのものではないが開発を支える地味な作業を担当した。誰も手を挙げない領域を率先して巻き取ることが、「最終的な判断をする人」という自分の役割を実質的に支えていたと思う。

最終的には、当初決めていた役割そのものも変化した。開発当初は「tkisaku=最終判断者、ikawamuk=コード品質、kokurita=PM」という設定だったが、実際の開発が進む中で自分がPM的な立場を担うようになり、ikawamukはコード品質担保役のまま、kokuritaはコードレビューに特化するという構成に変わっていった。最初に決めた役割は、チームの実際の動き方や得意分野が見えてくる中で自然と組み替わっていった。

技術的な功績 — HTTPRequestParser

自分が最も深く関わり、誇れる部分はHTTPRequestParserの実装。

このプロジェクトはHTTP/1.0サーバーとして仕様策定したが、実装にあたってはRFC 9110(HTTP Semantics)・RFC 9112(HTTP/1.1)・RFC 1945(HTTP/1.0)を横断して読み込んだ。単に文法をどう解析するかというシンタックスの理解だけでなく、各仕様が何を意図しているのか、なぜそのルールが存在するのかという意味的な理解まで踏み込んだ。

この理解の深さは、パーサー自体の実装だけでなく、チーム全体のサーバー設計判断にも影響を与えた。具体的には:

  • keep-aliveの扱い: keep-aliveを実装する場合、コネクションの扱いやパーサーの構造そのものが大きく変わることをRFCの理解から見抜き、チームに共有した
  • chunked parserの必要性判断: chunked transfer encodingに対応するパーサーが本当に必要かどうかを、仕様の意味から判断して提案した
  • 逐次パース(non-blocking I/Oとの整合性): サーバーをnon-blocking I/Oで構築している以上、リクエストを一度に読み切るのではなく、データが来た分だけ少しずつ読み進める逐次パーサーでなければ、そもそもnon-blockingにした意味がなくなる。これを設計上の必須要件として捉え、パーサーの構造に落とし込んだ

HTTPRequestParserの実装は、単体の機能としてだけでなく、「サーバー全体がどう振る舞うべきか」という設計判断の起点になっていた。RFCを読むという地味な作業が、コードを書く以前の意思決定の質を上げていたと思う。

苦労したこと・乗り越え方

「宿題」が機能しないという前提に気づいたこと

当初は各自が空いた時間に作業を進める想定だったが、メンバーが個別に時間を確保して進める、いわゆる「宿題」形式がうまく機能しないことが分かってきた。そこで方針を変え、宿題を前提にするのではなく、42に集まっている時間そのものを共有し、その時間内でwebservに関する作業を進めるという形にした。個人の自己管理に依存するのではなく、物理的に同じ時間・場所を共有することで進行を担保する、という解決策。

生活リズムを合わせたこと

チームメイトが夜型だったのに対し、自分は元来朝型だった。共有する時間を確保するために、自分の生活リズムを夜型側に合わせる形で調整した。

チーム内の空気を保つ役割

メンバーの一人のこだわりの強さが原因で、チームの空気が崩れる場面があった。その際は自分が間に入り、関係を取り持つ役割を担った。

チームで学んだこと

一人では到達できない作業量を、チームでなら実現できるということ。git fameの数字を見ても、複数人が並行して手を動かしたからこそ、2ヶ月強でHTTP/1.0サーバーという規模のプロジェクトが完成した。

ただ、それ以上に大きな学びは、視点の違う人間同士がぶつかり合うことの先にしか、良いプロジェクトは生まれないということ。設計の方向性、こだわりの置き所、進め方への考え方が人によって違う中で、それぞれの視点がぶつかることで初めて、一人では見えなかった盲点や改善点が見えてくる。

このぶつかり合いは、心地良いものではなかった。感情的に不快に感じる場面もあったし、楽な道ではなかった。それでも、そのプロセスを経た先には、確かに一人では作れなかったものができていた。

そしてその過程の先に、チームで実装することの楽しさがあった。不快さと楽しさは矛盾せず同時に存在していて、それがチーム開発の実感だった。