クラウドワークス エンジニアブログ

日本最大級のクラウドソーシング「クラウドワークス」の開発の裏側をお届けするエンジニアブログ

Gormのv1からv2へバージョンアップした話

こんにちは。クラウドログ事業推進部の甲斐です。 普段はWEBエンジニアとしてフロントエンド開発やバックエンドのAPI開発を担当しております。 クラウドログではオフショア開発を行なっているため、苦手意識のあった英語に苦戦しつつもフィリピンの開発メンバーと一丸となり日々精進しております。 今回は最近行った取り組みであるORMライブラリGormのバージョンアップ対応についてご紹介します。 具体的なコードの改修方法には触れていませんが影響範囲の大きいライブラリの移行を検討中の方に向けて施策の進め方の参考になれば幸いです。

Gormについて

クラウドログでは現在API開発にGoを使用しています。 Goで利用できるORMはSQLBoilerやentなど色々ありますがクラウドログではgithubのスター数も多く、比較的ネット上に情報も多いGormを利用しています。 Gormv2のリリース以降も長らくv1を使い続けてきましたがライブラリのアップデートによりいくつかのメリットも享受できる見込みだったためアップデートに踏み切りました。

目的

Gorm v1からv2へ移行する目的についてです。 利用したかった新機能など挙げるとキリがないですが、クラウドログとしては大きくは下記の3つとなります。

V1の開発が止まっていること

v2がリリースされたことにより、今後v1では改善や新機能追加によるメリットの享受が難しく開発が止まったライブラリを使い続けることはセキュリティリスクにも繋がります。多少の移行コストを払ってでもこのタイミングでv2へ移行すべきとチーム内で決定しました。

パフォーマンス改善が見込めること

Gorm v2は同じGormと言ってもフルスクラッチで書き直され内部の構造なども見直しが入っています。特にライブラリ利用者側が意識する大きな変更点としてはクエリの組み立て処理でインスタンスが使い回されるようになったことです。v1では内部的にcloneメソッドの呼び出しがあり毎回新しいインスタンスが返されていました。v2ではGCアロケーション削減のため構造体内部に持つフィールドが共有されます。

SQLのテストが簡単にできる

クラウドログではORMでのSQL組み立ての共通メソッドが多数存在しており、これまでそれらのパッケージに対してテストを行う場合、reflectパッケージなどを用いて無理やりテストを行なっていました。v2では新たに追加されたStatementフィールを参照することで簡単にSQLや引数などを取得できるようになっています。

どのように進めたか

次に移行の進め方について簡単にご紹介いたします。

リリースノートを確認して修正方針を固める

まず最初にリリースノートと既存のコードを確認しつつ修正方針を固めていきました。

公式ドキュメントに比較的丁寧にv2のリリース内容が記載されているので、セクションを1つずつ確認して記載のメソッドが自分達のコード上で利用されているか確認し修正方法についてissueのチケット上にTODOとして起こしていきました。 利用していたメソッドがv2で削除されていたりと戸惑う箇所はありましたが、修正方針について事前に検討しておくことでおおよそ移行にかかる工数を見積ることができました。

(この時点では「意外と楽勝かもな〜」なんて呑気に考えていました)

[チケットの抜粋]

テスト方針を策定する

大まかな方針としては、ユニットテストでカバーできているところ、できていないところを精査してカバーできている箇所に関してはユニットテストのクリアを持って移行完了と見なし、できていないところに対してはその機能のリリース時に行ったテスト仕様書をもとに再度テストを行っていくことにしました。 余談ですが、クラウドログのユニットテストはエンドポイントからDBまで一気通貫で動作を検証する方針をとっています。(デトロイト派)

そのため移行中もユニットテストを動かしながら実装を行うことで、機能として壊れていないことを確認しながら安心して作業を進めることができました。 改めてユニットテストの大事さを実感しました。

修正実施 & テスト

最初に修正箇所については検討をつけていたのでビルドを通すところまでは一瞬で完了できました。が、一筋縄ではいかずかなり苦戦しました。基本的には移行前と移行後に出力されるSQLを比較したり、Gormのソースコード読みながら地道に修正を進めてなんとか完了できました。

(1回のレビュー依頼で220ファイルほどの変更を入れる暴挙を働いたにも関わらず、レビューしていただきました皆様、本当にありがとうございました。)

テストに関してはフィリピン開発メンバーにも協力してもらいながら円滑に進めることができました。ここでも事前にテスト方針に関するドキュメントを整理していたので連携がスムーズにいきました。

メンバー全員に変更点と修正方法を共有

移行完了後、開発メンバー全員に向けて変更点と修正方法の共有会を行いました。

ライブラリのアップデートを行うにあたり、どのような変更があり、それをクラウドログとしてどのように修正していくかについてドキュメントにまとめてはいましたが開発メンバー全員に確実に伝達するために毎週行っている開発者勉強会の時間を利用して共有会を行いました。 私は英語にかなり不安がありましたので開発メンバーの内山さん(英語ペラペラ)に逐次通訳をお願いしフィリピンメンバーにもしっかりと情報を共有することができました。(内山さんありがとうございました)

注意すべきポイント

移行するにあたり注意すべきポイントを簡単に紹介させていただきます。

(修正したコードについては後日アドベントカレンダーにて書かせて頂こうと考えていますのでここでは具体的なコードに触れるものは記載しません。)

クエリ組立メソッド呼び出し時の副作用

先にも触れましたがv2ではクエリ組み立てメソッドに副作用があるため適切にSessionメソッドを呼び出す必要があります。 v1ではクエリ組み立てメソッド呼び出しの度に新しいインスタンスが返却されていたので、意識しなくとも途中まで作成したクエリを流用して別の複数のクエリを組み立てることが可能でした。しかしv2からはSessionメソッドの呼び出しがない場合クエリが汚染され意図しないSQLが発行されることになります。 シンプルなクエリであれば簡単に修正可能ですが、複雑なクエリ組み立てであったり自分の知らない機能を変更する際は一旦コードを読み込む必要があったため大変でした。

Scopesメソッドの実行タイミングの変更

個人的にはこの変更の修正が一番大変でした。 v1ではScopesに渡された共通処理は即時にクエリに反映されていましたが、v2のScopesメソッドは呼び出し時に即時実行されずfinisher_api系のメソッドの呼び出し時にまとめて実行されます。 気づいてしまえば修正は簡単でしたが、リリースノートにも記載がなかった(はず)のでかなり苦しめられました。

ユニットテストが必要不可欠

今回ライブラリ移行においてユニットテストの存在が不可欠でした。 もし、ユニットテストがここまで揃っていなかったら移行は不可能でした。 出来たとしても、全ての関連する機能に対して網羅的にテストする必要があるので莫大な時間が掛かってしまったことでしょう。 今回のケースのように影響範囲の広い改修が必要なケースでもユニットテストは非常に役に立つのでまだ導入されていない方が是非とも導入検討をお勧めします。

まとめ

今回の移行作業を通してバックエンド開発のキモであるORMのGormについてより深く知る機会になりとても良い経験になったと感じています。

また、現状の実装を改めて見直す機会にもなりユニットテストの改善案やその他いくつかの課題を発見することができとても有意義な施策となりました。

採用について

クラウドログではGoによるAPI開発を一緒に進めていただけるエンジニアの方を募集しています。 少しでも興味のある方がいらっしゃいましたら是非とも一度カジュアルにお話ししてみませんか??

ご応募お待ちしております!!

© 2016 CrowdWorks, Inc., All rights reserved.