2014-03-21

新卒で入社してからの1年間を振り返ってみる

2013年4月に新卒で入社してから大体1年くらい経ったので1年間を振り返ってみる。 殆ど技術的な仕事の話。
今ではできるようになっていることもあるけど、その時その時は初めて知ることで、理解するので精一杯だったことなどを思い出している。

1. WebAPI開発

研修を終えて、一番最初に担当したのは新規サービスのWebAPI開発だった。
これを、同じチームに配属された新卒メンバー4人で担当した。
WebAPIを使ったことはあるけれど、作るのはみんな初めてだった。

1-1. 仕様書設計

最初に、みんなでWebAPIの仕様書を作った。
リクエストボディを使うべきところでクエリパラメータを使ってしまったり、リクエストボディをどう受け取ればいいか等、随所で悩んだ。WebAPI設計は奥が深い。
他にも、PUTやDELETEなどのHTTPメソッドもWebAPIの用途に合わせて適切に使うよう設計したりもしたんだけど、他チームは謎のレガシーな環境でうちのAPIを叩く必要があるとかで、POSTじゃないとダメだとかで揉めたりもした。

仕様を考える上で、『Webを支える技術』はとても参考になった。 また、当時は知らなかったけど、『Web API Design』という書籍の翻訳サイトもすごく参考になった。

1-2. 開発

言語はPHPで行った。
新卒4人でそれぞれ独立してコードを書いていたので、それぞれが同じような処理を書いていたり、勝手にクラスや関数を作ったりしてすごい汚いコードができた。ちゃんとクラスの設計とかして、うまいこと分担できていれば良かったなぁとは思うものの、初めて知り合った4人でそれは難しい気もしている。

WebAPIの開発時、前々から興味を持っていたユニットテストを個人的に導入してみた。
といっても何をどう書けばいいか全然わからなかったので、『JUnit実践入門』と http://phpunit.de/manual/3.7/ja/ を参考にした。
色々と参考にして頑張ってはみたものの、今見るとダメなところがよくわかるかんじだった。 とは言っても、こういうのは書いていかないとどうしようもない気もしているので、最初のステップとしては良かったなと思う。

新卒4人がダメダメな汚いコードを書く中で、やっぱり先輩のコードはとても綺麗で読みやすかった。
自分レベルが読んでも、何をやっているのかがよくわかるコードだった。
先輩いわく、何年もやってきてようやくこのレベルまでたどり着いた感じだと言っていた。
もし綺麗なコードを書きたいならデザインパターンだけは知っておいた方が良いとのアドバイスをいただいたので、『Rubyによるデザインパターン』とかを読んだ。全部で10パターンくらいしか目を通していないので、続きは来年度にでも読んでいきたい。

1-3. リリース準備

自分の担当分が概ね終わったリリース時になって、ようやくインフラ部分を見る余裕ができてきた。
サーバ構成とかセットアップは全部先輩がやってくれたのだけど、その構成を理解するのが結構難しかった。学生の頃にWebサービスもどきを作ったことはあったけど、そんなのはVPS1台に全てまとまってるし、冗長化とか負荷分散なんてこれっぽっちも考えてない。

VIPを使った冗長化や、機能毎に分割されたサーバとか、ロードバランサーによる負荷分散とかしっかりされていた。こんなこと、企業なら当たり前かもしれないけど、見てるのは楽しかった。
インフラなんて絶対やりたくないと入社前は思っていたけど、サービスのアクセス数や負荷を考えて構成を考えるのも楽しそうだなと思えるようになった。

他にも、WebAPIとかフロントエンドのコードはパッケージ化して、それをyumとかaptみたいなパッケージ管理ツールのコマンド一発で、あるべきところに配置するなんてのもやっていて、当たり前と言われれば当たり前なのかもしれないけど、初めて知った時は驚いた。

そんなこんなで、インフラ系の知識にも興味をもったので、なんとなく『サーバ・インフラを支える技術』などを買って読んでみたけど、わからないところも多く、まだ前半部分しか読めてない。

1-4. 運用

リリースが無事に終わり、運用期に入った。 とはいっても何をすればいいの的な感じで、最初はのらりくらりしてた。しかしやはり新卒が書いたコード。バグは当然出てきた。

このとき、バグの原因を探ろうと思ったのだけど、探ろうにもログをまともに吐いていないことに気がついた。えらく断片的な情報しかログに落としていなかったので、原因調査は困難を極めた。 そんなのが2,3回続いたので、ログ出力の箇所を全員で各々修正をすることになった。

ログがなければ運用時に何もできないということを悟り、ログの重要性をはじめて理解した。 日時、プロセスID、ファイル名、関数名、リクエスト、レスポンス等は最低でもログに落とさないとエラーに対応できないし、サービスを改善していくこともできないと分かった。

2. DB設計・ライブラリ開発

WebAPI開発の次に担当したのは、新規サービスのDB設計・開発だった。

2-1. DB設計

DBの設計は過去に何度かやったことがあった。といってもその時は、ただデータを保存することが目的で、正規化を満たすことくらいしか意識していなかった。

良い機会だったので、イチから学び直そうと気合が入っていた。
気合のまま、『達人に学ぶDB設計徹底指南書』と『SQLアンチパターン』を買って、勤務時間や通勤時間で読んでいた。外部キー制約、正規化、インデックス設計、代理キーと自然キーとかを改めて学び、それなりに理解が深まったと思う。
制約は可能な限り付与して、DBに不正なデータが入らないようにする。アプリケーション側のバリデーションだけでは漏れてしまう可能性があるので、DBが最後の砦となってデータの正当性を担保するような設計が大切だと思った。また、運用においてDBの値を直接更新するような事態は可能な限り避けることも、重要であると理解した。

2-2. DBライブラリ開発

設計のあとはDBライブラリの開発を担当した。 先輩の趣向(?)もあり、開発言語はC++になった。最初はC++でWebAPIとDBライブラリを開発すると聞いて驚いたけど、できてみるとやはり高速で笑った。

WebAPI開発時の反省を活かして、重複処理や複雑すぎる処理をなくしたり、Strategyパターンを使って、整ったコードになる努力をした。今見てみると、やっぱりまだまだだと思う反面、前回よりは良いと自信を持って言えるので、そういう意味では良かった。

また、今回はエラーハンドリングの重要性を何度も教えられた。 関数やメソッドが成功する前提でコードを書いているところが一杯あって、こういうのがあると想定外の引数なんかを受取った時にプログラムが終了してしまう。
これもまた、言われてみると当たり前だけどその意識はその当時の自分にはほとんど無かった。
以下はPHPでchdir()関数を呼び出すときの例。

<?php
// chdirが成功する前提で書いている

chdir($path);
// 何らかの処理
<?php
// chdirが失敗することも考えている

if (chdir($path) === false) {
    // falseを返したり、エラーを吐いたりする
    return false;
}

// 何らかの処理

2-3. 負荷テスト

DBライブラリ開発が終わった後は、サービスの負荷テストを担当した。 開発しているWebサービスが想定しているリクエストを捌けるか、またこのシステムの限界性能はどこまでかを測定した。 負荷生成ツールなるものの存在もここで初めて知り、色々調べた結果、JMeterを使うことにした。今思うと、そんな複雑なサービスじゃなかったし、ApacheBenchで良かったなぁなどと思う。

JMeterは結構高機能でなんでも色々できてしまうので、初めて触った自分には慣れるまで結構時間がかかった。また、参考になる書籍やネット上のリソースはあまりなくて、結構苦労した。『ソフトウェアテスト総集編』なんかを買ってみたけど、結局あまり読まなかった。
時間をかけた割に満足のいく負荷テストはできていないけど、フロントエンドサーバのボトルネックを見つけて解消することができたし、その後負荷的な問題は発生していないのでとりあえずよかった。

ちなみに、ボトルネックはテンプレートエンジンのTwigで、これが原因でCPU使用率が80%を超えていた。
Twigのキャッシュ機能を使っていなかったのがよくなくて、キャッシュ機能を使う設定を加えることで解消された。

2-4. 機能拡張・改善

運用の話はさっきしたので、ここではリリース後の機能開発やエラー改善などについて。 基本的に担当者はコードを書いた人になるのだけど、その人だけに全てを任せるのは良くない。
ということで、流行り(?)のPullRequestを使った開発体制を採用することになった。これで、必ずメンバーのレビューを通してコードをデプロイすることを目指した。

まだまだ改善の余地はあると思うけれど、masterに直接pushしてしまうような開発体制よりずっと良いと思うし、メンバーが協調して開発を行っているような感覚になれるのは楽しい。

また、gitの運用方法もGithub-flowかgit-flowをとりあえず使ってみよう的な流れになって、なんとなく難しそうなgit-flowから導入することになった。 しかし、複数人で頻繁に変更をしているわけでもないので、Github-flowの方がシンプルで良いんじゃないかという流れになり、今はGithub−flowに変わった。なんかここはあまり上手に運用できていないので、今後改善していきたいなぁと思う。

というわけで、最近出たこの本読んでみたい。

3. CI導入

2つのサービスの開発案件が終わり、最近やっているのはこれらのサービスにCIの導入をする仕事。 CIはずっとやってみたいなぁと思っていたのでとても都合が良かった。 CIの概要を知るために買った『継続的インテグレーション入門』はすごく良かった。ちょっと古い内容も含まれているけど、あまり気にならなかった。

Jenkinsを使って、ユニットテストの自動実行、コードドキュメントの自動生成、コードカバレッジ測定、コード規約チェックや静的解析などを導入した。
Jenkinsがちゃんと動くとほんとに楽しい。 とは言っても、肝心のユニットテストが満足に書かれていないので、この辺りは喫緊の課題だと思う。

高いカバレッジ率のユニットテスト、ドキュメントコメントの徹底、コード規約への順守などを無理のない範囲で導入できたらいいなぁと思っている。 そうすればコード全体の品質が上がるし、サービスを引き継ぐことになっても胸を張って引き継げると思う。

4. 所感

1年間、短いようで振り返ってみると色々あったと再認識。
自分がどんなことに興味を持っているとか、どんなところにこだわりを持っているかとかも結構クリアになってきたし、有意義な1年だったと思う。

個人的に、ソフトウェアの品質にはこだわりたいなぁと思っていて、「動けば良い」という発想で書かれたコードを見ると結構苛立つ。 できないなりにも、出来る限りの品質を高める努力はしたいし、そういう人にはまわりのエンジニアが喜んで手を差し伸べてくれるものだと思う。

動くのは当たり前で、どれだけ品質の高いソフトウェアを作れるか。来年はそんなことを意識して取り組みたい。