実践クリーンアーキテクチャ - 複雑化した大規模ECサイトをモダナイズしたモノタロウの事例

クリーンアーキテクチャのメリットとは?またいかにして導入するか?難解なイメージのあるクリーンアーキテクチャの概要を採用事例に学びます。今回、取材したのは工業用間接資材オンラインストアの「モノタロウ」。サービスの開発を続けていくにつれ、同社のシステムは複雑化、肥大化していき、様々な課題が生じたそうです。こうした課題に対応すべく、システムのモダナイゼーションに取り組む際、取り入れたのは、クリーンアーキテクチャでした。同アーキテクチャをどのように実装したのか、モノタロウのエンジニア3人に聞きました。

実践クリーンアーキテクチャ - 複雑化した大規模ECサイトをモダナイズしたモノタロウの事例

「レガシー化したシステムをどうやってメンテナンスし続けるか?」は、サービスを長年運営してきた企業の多くが直面するテーマです。15年以上の歴史を持つ、事業者向け工業用間接資材オンラインストア「モノタロウ」も、このテーマと向き合ってきました。

サービスの開発を続けていくにつれ「システム構成が複雑になり、リリースや障害箇所の特定に時間がかかる」「自動テストが書かれておらず、ソフトウェアが大きくなるにつれ品質を保つのが難しくなる」などの課題が徐々に表面化してきたのです。

この課題を解決するため、サービスの開発者たちは数年前から、システムのモダナイゼーションに取り組んでいます。今回は彼らに、長い歴史を持つシステムを刷新するノウハウを解説していただきました。

1
金谷敦志さん(かなや・あつし/2@todogzm3todoa2c)(写真中央)
企業向け検索エンジン開発、北米市場向けソーシャルマーケティングサービス開発を経験後、2014年にMonotaROに入社。モノタロウのサイト開発を中心に、新EC基盤へのモダナイゼーションを実現するために必要な施策にも取り組み中。Developer Summit 2019 Summer, PyCon JP 2016セッション/2015 LTに登壇。
藤本洋一さん(ふじもと・よういち/4@_fp5fpt)(写真左)
組み込みソフトウェアやB2B・B2Cサービスのバックエンド・フロントエンドを経験後、2019年にMonotaROに入社。新EC基盤でのデータパイプライン実現に向けて奮闘中。Cloud Spannerの機能追加やApache BeamのGo対応改善を夢見る日々を送る。Go Conference 2019 Autumn登壇。ブログでの情報発信も活発に行う。
芝本雅史さん(しばもと・まさし/6@silver_birder7Silver-birder)(写真右)
Web技術の関心が強いエンジニア。新卒でSE企業に就職し、Webアプリケーション開発の上流~下流工程を経験後、2018年にMonotaROへ入社。主に、Webアプリケーションのシステムリプレースに従事している。モノリスで密結合したWebアプリケーションに対して、様々なアプローチを用いて疎結合なものへと再構築中。著書に『はじめてのWebComponents入門』がある。ポートフォリオサイトはこちら

受け入れテストを自動化し、システムの正常動作を保証

──「モノタロウ」は15年以上も前に生まれたEコマースサイトだそうですが、プログラミング言語やフレームワークは何を使用していますか?

金谷 プログラミング言語はPythonを使用しています。用いているフレームワークは、当社の独自実装のものです。「モノタロウ」の開発が立ち上がったばかりの頃は、デファクトスタンダードといえるPythonのWebフレームワークが、まだ世の中に存在していなかったためです。

──独自実装のフレームワークですと、メンテナンスが大変そうですね。

金谷 そうです。メジャーなフレームワークの場合、何か問題が発生したときでもWebや書籍の情報をもとに解決できますが、独自実装のフレームワークではそれができません。機能追加や不具合調査に時間がかかっていました。

さらに、システムのメンテナンスが続けられていくなかで、設計が複雑になり、ソースコードのコピー&ペーストも多くなっていました。新しいメンバーが参画した際の、システムの学習コストも高くなっていたのです。他にも、ユニットテストや受け入れテストのテストコードが全く書かれていないという課題もあり、手動テストに多くの時間を割く必要がありました。

8

──大変な状況ですね……。その課題を解決するため、システムのモダナイゼーションを始めたのですか?

金谷 はい。私は2016年頃から運用改善に取り組んでおり、改善初期はリリースの自動化やデプロイパイプラインの構築を行いました。その際に、「自動デプロイされたシステムが正常に動くかどうかを、end-to-endでテストしたい」というニーズが出てきたのです。そこで、受け入れテストの自動化をスタートしました。

──受け入れテスト自動化のために、何に取り組みましたか?

金谷 テスト自動化フレームワークである「Robot Framework」を導入しました。これは、当社のPythonスペシャリストである増田泰というエンジニアが薦めてくれたものです。

「Robot Framework」では、自然言語を用いてテストケースを記述することができます。シナリオと画面固有の操作を分離する「Page Object Pattern」というデザインパターンに合わせて、シナリオと画面固有の操作を明確に分けるように早い段階で設計しました。

シナリオにはテストしたい動きを自然言語で記述し、自然言語と紐付く具体的な動作を画面固有の操作をまとめたファイルに記述しました。画面の修正に応じて画面固有の操作を修正することはありますが、シナリオにまで影響することはありません。「Robot Framework」自体の使いやすさと相まって、非常にメンテナンスしやすいです。

「Robot Framework」がPython製なのも当社にはマッチしていました。「モノタロウ」の開発をPythonで行っているため、メンバーの端末には必ずPythonがインストールされているからです。

──「Robot Framework」の導入により、どのような変化が生じましたか?

芝本 リリース時の安心感が段違いになりました。「モノタロウ」はシステムの規模が大きいので、全機能を人の手だけでテストすることは不可能です。ですが「Robot Framework」でテストを書いておくことで「ユーザーがよく使う操作は、正しく動くことを自動テストが保証する」という状態を保てるようになりました。

ユニットテスト導入の秘訣は「テストを書くハードルを下げる」こと

──受け入れテスト自動化の後は、何に取り組みましたか?

金谷 開発のより早い段階で機能をテストできるように「ユニットテストのテストコードを書こう」という流れになりました。

──メンバーにテストコードを書いてもらうため、どのような工夫をしましたか?

金谷 「テストを書くためのハードルを極力下げる」ことに注力しました。例えば、当社は一部のエンジニアがWindows端末で開発をしていますが、ユニットテストに必要なPythonライブラリのなかには、Windows上ではうまく動作しないものがあります。

その課題を解決するため、コンテナを用いて環境構築をし、コンテナ上でユニットテストを動かす方針にしました。もう1つのハードルになっていたのが「メンバーがユニットテストを書くことに慣れておらず、どのように手をつけたらいいのかわからない」という課題でした。

──その課題を、どうやって解決しましたか?

金谷 テスト駆動開発(Test Driven Development)について実習形式で学ぶ、社内向け勉強会を実施しました。サンプルアプリケーションをテスト駆動開発のお作法1に則って開発してもらうことで、「ユニットテストはこうやって書けばいい」という感覚をメンバーに掴んでもらったのです。

おかげで、テスト駆動開発に取り組む人が増え、「モノタロウ」のユニットテストは徐々に増加していきました。現在(2019年11月の取材時点)では、約2,500ケースほどの量になっています。

──かなり増加しましたね。ユニットテストの導入により、開発フローそのものも改善されたのでは?

芝本 ソフトウェアの品質が向上したのはもちろんですが、ユニットテストがあることで、ソースコードレビューの際に「開発者はどんな動作を想定してコードを修正したのか」が明確になりました。Pull Requestの説明文だけではなく、テストコードの内容からも修正の意図が読み取れるようになったからです。ユニットテストを書く文化が生まれたことで、レビューする側の負担も軽減されました。

クリーンアーキテクチャ化は、“幹”の処理から手をつける

──他にはどのようなシステム改善を行いましたか?

芝本 私たちのチームでは、システムのクリーンアーキテクチャ化を実施しました。最初に手をつけたのは検索ページです。

9

クリーンアーキテクチャはRovert C. Martin氏が提唱した設計思想。ソフトウェアの各コンポーネントを「ビジネスロジックを表現するレイヤー」「アプリケーションができることを示すレイヤー」「入力・永続化・表示を担当するレイヤー」「フレームワーク固有の処理やデータベースへの操作などを表現するレイヤー」という4層に分け、同心円の外側にあるレイヤーを内側にあるレイヤーにのみ依存させる。図はThe Clean Code Blogより引用。

──クリーンアーキテクチャを選択したのはなぜでしょうか?

芝本 各処理を疎結合にし、独自実装のフレームワークに依存している処理を、他のフレームワークに代替可能な状態にしたかったためです。クリーンアーキテクチャは依存の方向性が単一方向であり双方向依存がありません。フレームワーク固有の処理などレイヤーの外側に存在する要素は、置き換えがしやすくなります。

それから私たちのチームでも、過去にはユニットテストがほとんど書かれてこなかったため、今後はなるべくテストコードを増やしていきたい。ですが、旧来のアーキテクチャでは、モックを差し込むことが困難でした。

クリーンアーキテクチャを採用すれば、その課題も解決しやすくなります。各レイヤーが抽象に対してのみ依存しているため、モックを挟みこむのが容易だからです。

──「モノタロウ」の検索ページは、それなりに規模の大きなシステムかと思います。どのようにして、改修を進めていったのですか?

芝本 機能のなかでも“幹”といえる処理の設計から着手していきました。

10

──“幹”とはどういうことでしょうか?

芝本 検索ページのなかには、キーワード検索はもちろん、商品カテゴリによる検索など多種多様な検索ページが存在します。そのうち、検索ページの根幹といえるのはキーワード検索です。この機能を“幹”と呼び、他の機能を“枝”と呼んでいました。前者の機能を、まずはクリーンアーキテクチャ化していくと決めました。

──どのような手順で、幹を設計していくのでしょうか?

芝本 設計を始めた段階では、いったんすべての処理をユースケース層に置いてしまいます。

11

その後、チーム内で議論し合いながら、それぞれの処理を適切な層へと移していくわけです。例えば、APIの呼び出しが発生するのならば、その処理をリポジトリ層に移譲します。

12

APIから取得したデータを加工する処理があれば、画面表示のための加工ならばプレゼンター層に、業務ロジックのための加工ならばドメイン層に置くというように「処理の目的に応じて、適切な層にふり分けていく」という形で設計を行いました。

13

幹の処理の設計方針が決まってからは、枝の処理にも同様の設計を適用していきました。

クリーンアーキテクチャを全社的に展開するために

エンジニアHubに会員登録すると
続きをお読みいただけます(無料)。
登録のメリット
  • すべての過去記事を読める
  • 過去のウェビナー動画を
    視聴できる
  • 企業やエージェントから
    スカウトが届く