田中氏の自己紹介

田中晋太朗氏:はじめまして、ワンキャリアの田中です。私からは「モジュラモノリス構想」と題して、我々ワンキャリアが抱えている課題感であったり、これまでに試してきたこと、それからこれから試していこうと思っていること、構想の話をしていきます。

本題に入る前に軽く自己紹介させてください。株式会社ワンキャリア・CTOの田中と申します。過去、テック系のスタートアップを起業したり売却したりとかという経験をしつつも、2018年にワンキャリアの1人目のエンジニアとしてジョインして、以降CTOを務めています。

それからちょっと余談ですが、最近ハマっている趣味というか……。なぜかこのタイミングでアマチュア無線の免許を取って、最近ハマっているようなところです。

本題に戻ります。本日の流れは、ワンキャリアの事業の紹介のあと、ワンキャリアの開発が抱えている課題を話して、それに対して今までどういうことを試してきたのか、それからこれからどういうことをやっていきたいのかを話していきます。

一言お断りしておくと、モジュラモノリスというところで考えた時に、ワンキャリアの状況は前に発表されてた2社さん(株式会社タイミー、株式会社hacomono)と比べても一番遅れている状況というか。これからやっていくところも非常に多いし、検証しながらやっていく中で、構想は軌道修正とかしていくべきところも多々含まれると思っています。

なので、半分実話でありつつ、半分構想というか私の空想みたいなところが含まれると思って理解いただければ幸いだと思っています。

ワンキャリアが提供している3つのサービス

では、最初にワンキャリアのことを少し説明させてください。ワンキャリアは「人の数だけ、キャリアをつくる。」というコーポレートミッションの下、ユーザーの方の就職活動、転職活動、採用活動を支援する各種事業をやっています。

「じゃあどんなサービスなの?」というところで、大きく分けて3つあります。採用活動をしている人事向けの「ONE CAREER CLOUD」と新卒の就活生向けの「ONE CAREER」、中途の転職者向けの「ONE CAREER PLUS」というところで。

どのサービスもUser Generated Contents(UGC)とかクチコミ、体験談を求職者の方から集めて、いろいろ就職活動をやっている方々、求人している会社の採用設計とかを改善していくようなサービスになっています。

この3つのサービスの中で最初にリリースしたのが、社名と同じですが「ONE CAREER」です。2013年にサービスを立ち上げて以来……。私が入社する前からあったサービスなんですけど、がんばって開発してコンテンツ数も増やしてきて、その結果として、最近だとHR総研さんの調査結果で「学生が1年で最も使うサイト」で2位になっている。1位ではありませんが、2位になっているといったかたちで、ユーザー数を伸ばしています。

この裏には、先ほども少し触れたクチコミとか体験談とかのデータをたくさん集めてきて、その後のキャリア選びのために役立てるというところで、キャリアデータをたくさん集めて価値提供しているというところがワンキャリアの特徴になっています。

このデータを集めるというのはなにも就活生からだけではなくて、中途の方からもデータはたくさん、多角的に集めていこうとしています。「ONE CAREER CLOUD」を使っている人事の方からもどんどんデータを集めていこうというところで、「ONE CAREER CLOUD」もまた、機能的にもどんどん最近増えていって、いろいろな機能を提供するようになってきています。

もうちょっと具体的に言うと、最初は「ONE CAREER」に求人情報を載せる管理画面的な意味合いが強いサービスだったんですが、スカウトの機能であったり、応募者管理をできるような機能であったり、どんどんと機能が追加されていっているというところです。

こういったかたちで機能がどんどん拡充される中で、全面的にキャリアデータを集めていくようなサイクルを回しながら、ワンキャリアのデータを事業に活かしていくというようなことをしています。

ここで本題に関わるところに話を戻すと、データ活用をどんどん活性化させていけばさせていくほど、ワンキャリアのサービス、今時点で「ONE CAREER CLOUD」と「ONE CAREER」と「ONE CAREER PLUS」ありますが、各サービスが同じデータソースにどんどんアクセスするような状況が生まれます。

こういった状況って、やはりデータを上手にモデリングしてあげて、アーキテクチャ的にも上手にアーキテクチャ設計してあげないと苦しいことになりそうだなみたいなところを察することができる部分かなと思っています。

しかも、今後もサービスは増えていく予定もあるので、ますますアーキテクチャの部分は大事になってくるなというところです。

データベースが“大きな泥だんご”状態になっている

ということで「アーキテクチャの部分は大事ですよ」という話につなげたところで、「実際にじゃあワンキャリア、何に困っているんでしたっけ?」というところを説明させてもらえればと思っています。

今日の会議のテーマとこれまでのお話の中で大部分お察しなのかなと思っていますが、開発がちょっとずつ大変になってきました。実際蓋を開けてみると、UGC、ユーザーの投稿データはたくさん集めてきましたが、昔集めたデータと新しいデータで仕様が変わっていたりして。互換性のためのコードがたくさん入っていたりとかもしますし。

そのデータに触る人は、学生だったりすることもあれば、人事、企業の人事だったりすることもあれば、弊社の社内のサービス管理者だったりすることもあるんですけど、それぞれ違うアクターのユースケースが、1つのクラスの中に全部書かれていたりとかもしていました。

同じデータベースを複数のサービスから参照していたりするので、データベースのマイグレーションもけっこう大変だというところで、いわゆる“大きな泥だんご”と言われているような状態であると理解いただければと思っています。

つまるところ、何か変更するにも変更影響に恐怖しながらやってきたというところですね。

というところが3年前までの状況ですでにあったんですが、それから何をしてきたかというと、実はマイクロサービスとかモジュラモノリスとか、そういう垂直分割をするアプローチをちょっと避けていた期間があります。

水平分割をやって多少良くなった

じゃあどんな取り組みをしてきたのかというところを、少し紹介させてください。例えば、今回の趣旨からは大きく外れますが、「スキルが高ければなんとかなるんじゃないか?」みたいな話も出て、スキルアップのための施策をいろいろ打ったりもしてきました。

アーキテクチャの部分で言えば、レイヤードアーキテクチャというか、オニオンアーキテクチャをベースとした考え方を取り入れてるようなこともしてきましたし、「データベース分割できないかな?」みたいな取り組みもしてきました。

今回の趣旨に照らして、レイヤードアーキテクチャの導入をがんばってみたみたいなところを、モジュラモノリスの話に入る前に少しお話しします。

3年ぐらい前のワンキャリアのコードを……。ちょっと色が薄くてもしかしたら見にくいかもしれないですね。すみません。今も完全に解消したわけじゃないんですが、非常にファットなモデルだったんですね。まあ、よくある話だと思います。

先ほども言ったように、いろいろな立場の人が使う、いろいろな関心ごとに基づくユースケースがModelの中にごちゃまぜで書かれていたりしました。

Modelの本来の性質、何が本来の性質で、何がアプリケーション要件の実装なのかがパッと見わからないようなところもあったし、かといってユースケース全部をちゃんと寄せられているのかというと、Controllerに書かれている部分もあるというような、けっこうごちゃまぜの状態でした。

今日参加されている方だと、具体的な、例で説明するようなところはもしかしたら必要ないのかもしれないですが。

(スライドを示して)じゃあ弊社の当時のモデルどんなふうになってたのかみたいなところを少し例をもって説明すると、例えば(仮にECサイトのモデリングを考えると)こんな商品モデルがありました。

とある商品の税込価格を計算するロジックを含むようなモデルがあるんですが、なぜかそこにお得意さま割引の計算をするコードも含まれていたりするような、そんな状態です。実例ではないので、例えばこういう話ということです。

そうすると、この商品モデルって、お得意さまの話って商品じゃなくて顧客の話ですよね。そのモデルで取り扱う関心ごとではないことも、知らないと処理できないようなモデルになっていて。つまり、依存性の方向が逆転しているというところで、変更に弱いし、単純にわかりにくいみたいな状態が起こっていました。

なので、「いや、そもそもマイクロサービスとかモジュラモノリスとかあるけれど、そもそも水平分割うまくしていったほうがいいんじゃないの?」というところで、まず水平分割をやりました。

オニオンアーキテクチャとかを参考にしながら、ModelとかControllerからユースケースを切り出していくことをやってみました。

(スライドを示して)「Controller」「Application Service」「Domain Service」「Model」と一応置いています。このあたりの各レイヤーの責務はググったりして出てくる一般的なものから大きくは外れていませんが、ワンキャリアにおいてはこういう整理になっているというのが、Controllerはクライアントから、ブラウザからのリクエストを受け取って認証・認可しつつ、パラメータを解いて取り出してくる。それをApplication Serviceに渡します。

Application Serviceはアプリケーションのユースケースの実装ですね。手続き的な処理を担当して、必要に応じてDomain ServiceであったりModelにアクセスします。Domain Serviceはドメイン固有の手続き的な処理を書いていたりもします。ModelはRailsのActive Recordを扱うモデルというような整理になっています。

これをやってコードの見通しは多少良くなったなと思いますが、今日の会の趣旨に戻って、これでやはりすべて解決したわけではなかったというところで、まだ苦しい部分がありました。

「同じデータソースを見にいっている」ことは解決していない

(スライドを示して)結局、水平分割しても解決しないことというのがこれなんですね。弊社でいうと、「ONE CAREER CLOUD」「ONE CAREER」「ONE CAREER PLUS」、それから社内の管理サービスが「Admins」って書いてあるものなんですが、それらって、別のサービスとして実装されていてサーバーも別ですが、みんな同じデータソースを見にいっているというところが実際のところです。

水平分割はしたものの、例えば採用イベントのデータを格納しているテーブルにアクセスするモジュールというかサービスは、みんなこのモデルのことをよく理解しておかないとなかなか変更しづらいというのは、やはり変わらなかったというところです。まあ、当然といえば当然なんですけれども。

なので、例えば「ONE CAREER CLOUD」の開発者は、「ONE CAREER CLOUD」のロジックだけじゃなくて、「ONE CAREER」がこのモデルに対してどういうことをやっているのかとか、そういったところもある程度理解しておかないと扱えないような状態になっていました。

それでもサービスを壊さないようにしないといけなかったので、何か変更しようと思った時に、とても慎重にほかのサービスのこととかを調べるということをやりながら開発してきたわけですね。

怠ると障害が発生してしまうし、回避するために、自分の担当サービスじゃないところのコードを読みにいって変更影響の調査をしたり。それからそのドメインに詳しい人に話を聞きにいって変更影響を調査したりとか。

あとは、実際にリリースする前に、小さいリリースでもこのあたりを触る変更が含まれる場合は、CTOの私とかVPoEにレビューをもらおうというので、けっこうボトルネックになったりする瞬間とかもあったりして。調整工数がなかなかかかるというところで苦しんでいる状況になっています。

(次回に続く)