こんにちは、株式会社エアークローゼットの藤川です。
今までエンジニアの評価制度と、プロダクト開発の優先度を決める方法をご紹介してきましたが、弊社のシステムと考え方を紹介するために今回はCTOの辻がまとめた、「エアークローゼットを支えるシステムの歴史的な経緯とこれから」をご紹介します。
IT×ファッションで新しいあたりまえを創造してきたエアークローゼットのシステムついてご興味がある方、エアークローゼットのCTOにご興味がある方に読んでいただきたい内容となっています。かなり長文となりますが、ぜひご覧ください!
Profile
辻 亮佑 RYOSUKE TSUJI 1986年生まれ
ニックネーム:Ryan(ライアン)
上智大学卒業後、IT開発会社にシステムエンジニアとして入社。2012年に楽天にフロントエンドエンジニアとして入社し、2013年からはリードフロントエンドエンジニアとして活躍。2015年に株式会社ノイエジーク(後の株式会社エアークローゼット)に入社し執行役員CTOに就任。
自己紹介
はじめまして。株式会社エアークローゼットのCTOの辻です。2020年から着物にハマってほぼ毎日着物を着て生活しています。
大手では経験できない、1人でインフラからバックエンド、フロントエンドまで作り上げる経験を積み、エンジニアとして1から全てつくる経験をしたいと考え、創業期のエアークローゼットにボランティアとしてジョインしました。その後、正式にCTOとしてジョインし、現在10年目です。
いわゆる技術的負債に対しての対処の仕方ではなく、具体的にどういう経緯でシステムが変わってきたのか、なぜそのタイミングでその技術選定を行ったのか、そしてこれからどうしていくつもりなのかを書いていきます。
はじめに
ある時点でのシステムに対しての良し悪しや、目指すべき理想のシステム構成についての記事はよくあるものの、具体的にどうしてるのかわかるような記事はあまり見ないなと思いこのテーマにした次第です。
そのためサービス開発をしていく上で、プロダクトへの追加実装スピードと技術的負債とのトレードオフで悩んでいる方や、どうやって技術選定をしていくのか悩んでいる方、システム構成の方向性で悩んでいる方の一助になれば幸いと思っています!
エアークローゼットについて
エアークローゼットは「発想とITで、人々に日常に新しいワクワクを創造する」のMissionのもと、人のライフスタイルの中によりワクワクした体験を作っていくために、複数の事業展開を行っています。よくアパレル系の会社ととらえられることが多いですが、それ以上にITの力を信じている人が多いITベンチャーです!
そしてメインの事業が会社名と同じサービス名の女性向けファッションレンタルサービス"airCloset"です。
airClosetの特徴を簡単にまとめると、
1. ユーザーは洋服を選はず、洋服に関する好みの情報を登録する。
2. 登録された情報をもとにプロのスタイリストがスタイリングを行う。
(洋服を選んでコーディネートをつくり、アドバイスを作る。)
3. 2で登録された情報が倉庫に連携され、ユーザーの手元に実際にお洋服
が届く。
4. ユーザーは普段着としてその洋服を使い、気に入ったものは購入、そこ
まででもないものはフィードバックを記入し返却。
5. 返却が問題なくされたことを確認しだい、2に戻る。
このサービスを実現するために、まず最短で世に出すことをゴールにして開発されたのが一番最初のシステムです。
①サービス開始時(2015/2)のシステム開発
この頃はまだ私も前職の楽天で仕事をしていたこともあり、最初のシステムはCEOの天沼とCOOの前川が仕様をつくり、オフショアを使って開発を行っていました。創業期のスタートアップには当然のことですが、資金がかなり限られていたためです。
とくにairClosetのサービスを提供するためには、システムだけでなくお洋服、スタイリスト、倉庫及び倉庫オペレーションも必要になります。
そういった、システム以外のオペレーション構築や、洋服の買付などもあった中で、まずサービスを開始するために必要最低限なシステム構築を行ったのがこのときです。
具体的にはお客様が使うWebと、スタイリストが使うスタイリング機能や、登録されたユーザー情報や在庫情報を管理機能がのった管理Web、そして倉庫への発送指示や在庫情報の連携等を行うバッチシステムです。これを一つのrailsアプリケーションの中で全て開発していました。
理想的には一番最初が一番コスト低くきれいに作ることができるタイミングでもあるものの、実際にサービスを開始してみないとそれぞれの機能がちゃんと使われるのか、そもそもそのサービスが世の中から必要とされてるのかも全然わからないため、ここではそのように意思決定しています。
このシステムの課題
当然ですが全て同じアプリケーションにのって動いていたため、ユーザWebでシステムが止まると管理Webも止まる、とか同一ドメイン上で管理画面にもアクセスできてしまうなどがありました。一方で当然同じrepositoryに全部入ってるし、DBもひとつだしで開発効率が良いのが圧倒的なメリットですね笑
ちなみに、上にも書いたようにairClosetはシステムだけではなく、サービス運用するためのステークホルダーの数が非常に多く、また参考になる業務フローが存在しない中でそれを確立しオペレーションをまわす必要があるため、普通は創業まもないスタートアップがやるようなサービスではないなと今でも思ってます笑
ただこのときに構築した業務フローは現在でも大きく変わっておらず、サービスの屋台骨となっています。
②管理WebのReplace(2015/03 ~ 2015/09)
上で書いた最初のrailsアプリケーションは全部入りのなんでもアプリケーションだったため、とにかく最初に切り離したのが管理Webです。サービス開始後半年程度で完全リプレイスしています。
そう判断したのは、下記の3つの理由からです。
・とにかく管理Webが開かれている状態はセキュリティ上すぐにでも止め
たい。
・まず最初に追加したい機能が多い。
・3つの中で最も機能が少ない。
このときに管理画面構築のために選択した技術は、サーバサイドがNode.jsのexpress、フロントエンドがAngularJS(ver1.5)です。
それぞれの選択理由は下記です。
Node.js
フロントエンドとバックエンドで同じ言語で開発ができる
単純に頭の切り替えをしなくていいってこともそうなんですが、私自身の考えとして、エンジニアも技術だけではなくサービスにコミットして欲しいと考えています。なのでエアークローゼットではシステム開発というよりも、機能開発にエンジニアをアサインするような形をとっています。
そのためフロントエンドもバックエンドも関係なく、その機能開発に必要であればフロントエンドだろうがバックエンドだろうがそのエンジニアに開発を担当してもらう体制をとっており、そのときにどちらも同じ言語で開発できれば効率が良いと考えました。
script系言語の中ではパフォーマンスが良い
今ではハイパフォーマンスな言語としてはGoが一番良く知られていますが、当時はGo使っている会社なんてほとんど聞かなかったような頃でした。
その中でJavaScriptは主にV8の恩恵もあり、Pythonやrubyに比べてかなりパフォーマンスが良く、それもNode.jsを選択した理由です。
C10K問題を意識
マシンスペックも上がってきているからか最近あまり聞かなくなりましたが、いわゆるC10K問題が結構騒がれていた時期でした。まあNode.jsが最初それを売りにしていたっていうのもあるかもしれないですが。
C10K問題自体はここで説明するとまた長くなってしまうので気になった方は調べてみてください。とにかくNode.jsはJavaScriptの言語仕様上シングルスレッドで動作する特徴があり、C10K問題を回避することができるので選択してます。
PayPal等の西海岸ではすでに使われていた
2015年というとNode.jsで開発してる会社なんて日本ではほぼありませんでした。バージョンもまだ0.xだったし、iojs騒動もあった頃です笑
ただPayPalのような当時業界を引っ張っていた、かつ決済サービスでNode.jsを採用していたのでまあいけるだろうと思った次第です。
JavaScriptが好き
とはいいつつ結局これが全てかもしれません笑
MLやるならPythonとか外せないところはありつつ、最終的には自分が開発しててテンション上がらないと開発スピードも上がらないので、感情面も含めて一番プロダクト開発が捗る言語を選ぶのがベストだと思ってます!
express
Node.jsのフレームワークはあまり選択肢がなかったのもありますが、私自身はrailsやDjangoのようなフルスタックフレームワークが好きではなかったので、必要最小限のことしかしてくれない、必要なものは自分でつくる必要があるexpressが好きです。
フルスタックなフレームワークはとにかく最初に高速開発できることが圧倒的なメリットと思っている一方、勝手によしなにやってくれるため実装するエンジニアの知識の幅が広がらない、フレームワークのWayに逸れたことをしようとするとめっちゃ大変といったデメリットがあると考えています。
このときのエアークローゼットはすでにローンチまでは完了し、想定よりもずっと多くのお客様の登録も来ており、一定サービスは伸びていくと確信していたため、メリットよりもデメリットを重く見て軽量なフレームワークを選んだ経緯です。
AngularJS
AngularJSに関しては当時あまり選択肢がなかったのが実情です。まだ今ほどReactが伸びるって確信できるような情勢ではなかったし、ユーザーサイドは仮想DOMでパフォーマンスを考慮できるReact、管理画面はフルスタックで高速で開発ができるAngularって切り分けがよく言われていた時代で、その流れで選択しています。
③iOSアプリの開発(2015/11 ~ 2016/065)
もともとサブスクリプションのサービスでユーザーが継続的に使うサービスのため、WebよりもNativeアプリの方が相性が良いと考えており、比較的早いタイミングでNativeアプリの開発を行ってます。
Webから開発した理由
今良く言われるところのMVPを目指していたときに、アプリではなくWebの方が早いことと、まず集客が課題になると考えたときに、NativeアプリよりもよりもWebの方が相性が良いと考えたためです。
AndroidなしでiOSアプリを開発した理由
airClosetは忙しい女性向けのサービスで、かつファッションレンタルなんてそもそも世の中になかったサービスです。そうすると必然的に女性のアーリーアダプターがメインターゲットになってくるわけでして、そういったターゲット層が持っているスマートフォンはかなりiPhoneに偏っていたためです。
また、当時あったハイブリッドアプリの技術はcordovaのようなWebをベースにしたものが多くユーザー体験を損なう恐れがあったため、swiftでの開発を選択してます。
月額会員向けにのみ提供している理由
Nativeアプリは基本的にサービスを継続的に使ってもらうために開発するものと捉えています。エアークローゼットでいえば月額会員でない限りほぼ使える機能はなく、また集客はWebの方が向いていると考えているため、月額会員になるまではWeb、月額会員になってからはNativeアプリという設計を行っており、それは今でもそうなっています。
④バックエンドAPIの開発(2015/11 ~ 2016/08)
iOSアプリの開発と平行して、iOSアプリで使うためのバックエンドAPIをNode.jsのkoaを使って開発しました。Node.jsを採用しているのは管理Webに書いた理由と同様の理由のため、ここではkoaを採用した理由を書きます。
koaを採用した理由
そもそもkoaって聞き馴染みのない方も多いかなと思いますが、koaはexpressの開発チームが非同期処理をより扱いやすくするために開発したフレームワークです。たまにはこのへんでサンプルコードでも。
下記はexpressの公式に書いてあるサンプルコードですが、GET / にrequestを送ったら、'hello world'って文字がresponseとして返ってくるコードです。まあ見たままですね。
var express = require('express');
var app = express();
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
res.send('hello world');
});var express = require('express');
var app = express();
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
res.send('hello world');
});
copy
まあこれだけなら全然困らないんですが、例えば下記のように非同期処理を挟むケースがあります。
var express = require('express');
var app = express();
var mysql = require('mysql');
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
//DBからユーザ情報をとってきて
mysql.query('SELECT * FROM users WHERE id = 1;')
.then(userData) => {
// クライアントに返す
res.send(userData);
});
});
// こんなことはできない
app.get('/', function async (req, res) {
//DBからユーザ情報をとってきて
var userData = await mysql.query('SELECT * FROM users WHERE id = 1;');
// クライアントに返す
res.send(userData);
});var express = require('express');
var app = express();
var mysql = require('mysql');
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
//DBからユーザ情報をとってきて
mysql.query('SELECT * FROM users WHERE id = 1;')
.then(userData) => {
// クライアントに返す
res.send(userData);
});
});
// こんなことはできない
app.get('/', function async (req, res) {
//DBからユーザ情報をとってきて
var userData = await mysql.query('SELECT * FROM users WHERE id = 1;');
// クライアントに返す
res.send(userData);
});
copy
最近だとasync await を使って非同期処理を扱うのが一般的になってるので、つい下に書いた書き方がしたくなるものですが、expressがpromise形式のresponseに対応していないのでこんなことは書けないんです。
※ ちなみにわかりやすくexpressのsample codeに合わせて書いただけなので、今どきvar宣言かよ、とかORM使わないのかよとか、そこにDBアクセスする処理書くなよとかそういうことは気にしないでください!
これに対してkoaのサンプルコードはこちら。expressの課題を解決するためにつくられてるので大体想像つくかと思いますが。
const Koa = require('koa');
const app = new Koa();
const mysql = require('mysql');
// handlerにasync functionをかける
app.use(async (ctx, next) => {
await next();
//DBからユーザ情報をとってきて
const userData = await mysql.query('SELECT * FROM users WHERE id = 1;');
// クライアントに返す
res.send(userData);
});const Koa = require('koa');
const app = new Koa();
const mysql = require('mysql');
// handlerにasync functionをかける
app.use(async (ctx, next) => {
await next();
//DBからユーザ情報をとってきて
const userData = await mysql.query('SELECT * FROM users WHERE id = 1;');
// クライアントに返す
res.send(userData);
});
copy
見てわかるとおり、expressと見た目はほぼ一緒です。違うのはasync functionをhandlerに指定できることと、引数がちょっと違うくらいですね。
当時はasync / awaitの代わりにgeneratorが採用されてましたが、まあこんなふうにいい感じに非同期処理を扱いたかったのでkoaを採用してます。
⑤バッチ処理のreplace(2016/01 ~ 2016/06)
時期はたしかこれくらいの時期。それまでrailsで作られていたバッチをNode.jsベースのバッチに全て作り変えています。
Node.jsを採用した理由
管理WebをNode.jsでリプレイスし、継続的に追加開発していた経験から、Node.jsでアプリケーションを作っていくことに不安がなくなっていたのがまず前提にあります。
その上で、バッチ処理のためにrails使っているのはtoo muchだし、少数精鋭のエンジニアでやっていくにあたって開発言語が複数あることのデメリットを感じていました。
また、課金まわりの大きなシステム改修が必要となっていたため、既存のrailsアプリケーション上につくるよりも、そのタイミングでリプレイスしてしまおうと考えたのがきっかけでした。
⑥ユーザWebのreplace(2016/04 ~ 2016/08)
サービス開始当初使っていたシステムとしては一番最後にreplaceしたのがユーザWebです。とにかく当時はrails + jQueryの状態をいち早く脱却したかったわけですが、ここでは、それを決めた理由とReactを採用した理由を書いていきます。
replaceをこのタイミングで決めた理由
上に書いたiOS向けにAPIサーバをこのとき構築していたため、ほうっておくとWebとiOSで同じ機能を開発するときに、Node.jsのユーザ向けAPIとRailsアプリに同じ機能追加を行っていく必要がありました。
当然そんなことはバグを生む元になるし、二倍の工数もかかってしまうため、ここはかなり合理的に意思決定したつもりです。
Reactを採用した理由
2016/4時点ではもうReactは主流派になっていたため、ここでReact採用したのはとくに何も迷わずに決めています。一方で状態管理はまだ群雄割拠の時代で、fluxやらreduxやら複数ひしめいている頃でした。
このとき採用したのは、今ではもう2年半も開発が止まっているrefluxです。
reduxはどうしてもコード量が多くなってしまうことが好きではなく、storeとactionとcomponentだけの最低限構成で状態管理できることにメリットを感じrefluxを採用してます。今となってはやっちまった技術選定のひとつですが、当時はそれでサクサク開発進んだとは思うので後悔はしていません笑
⑦ユーザWebの新環境開発(2016/11 〜 2016/12)
replaceしたそばから新環境開発ってどういうことやねんって今振り返っても思うところなんですが、Reactに移行してひとつ困ったことがありました。
そう、C向けサービスの方なら誰もが悩まされるSEOです。
もともとairClosetはオーガニック流入のほとんどが指名検索だったのでそんなに困らないだろうと思っていたのですが、オーガニック流入を増やす施策もやっていきたい中で課題になったのでした。
そこで、当時Reactを使ったServer Side Renderingが出始めていたので、とりあえずやったろと思って作ったのがこの環境です。
とはいえその前に作ったReactの環境を利用して移行できるほど甘くはなかったのと、Next.jsもまだなかったので、新規で自前に構築しています。ちなみにこっちはreduxを採用して構築しています。半年の間にreduxへの流れができていたからですね。いやー、ほんとフロントエンドは流れが早い笑
最初はSEOが重要なページはこの環境で作る運用にしていたものの、メニューやヘッダなどどうしても二重管理になってしまうため、このあと徐々にこっちの環境にほとんどのページを移行しており現在に至ります。
⑧pickssサービスの新規開発(2017/05 〜 2017/09)
今はairCloset Fittingにサービス名が変わっていますが、airClosetの姉妹サービスとしてこの時期にpickssを開発しています。このときpickssで採用した技術は主に下記です。
・Node.js + express
・React + redux
・React Native
Node.js - express
もうこの頃エアークローゼットではNode.jsを使って開発するのが一番はやいって状態だったので、ここはとくに迷わず採用してます。
React Native
WebのフロントがReactで、バックエンドをNode.jsを採用して開発していると、当然出てくる選択肢がReact NativeでのNativeアプリ開発です。
そう思っていたころ、React Native JapanでReact Nativeを日本で広める活動をしていたユタマこたろう(YutamaKotaro)がエアークローゼットに入社することが決まりました。まさに出会うべくして出会った出会いでした!
そんなこともあり、迷うことなくReact Nativeで開発をすることに決定しました。
ちなみに本論からズレますが、このpickssサービスの開発はユタマこたろう(YutamaKotaro)と、当時まだ未経験だったエンジニアの2名体制でほぼ全ての機能開発を行っており、エアークローゼットで語り継がれている伝説の一つとなっています。
また、このあたりからDDDを設計手法に取り入れ始めており、これ移行に作っている環境ではDDDを意識して設計を行っています。
⑨倉庫連携システムreplace(2018/01 〜 2018/04)
この頃ビジネス的な理由から倉庫を移転することが決まりました。
それに伴い倉庫側のシステムも切り替わるため、それに合わせて倉庫連携のシステムも再構築が必要になったことが背景です。
さらに、もともと倉庫連携システムは⑤で開発したバッチ環境の上にのっかっていましたが、いわゆるスケジュールで実行したい処理が全てのっかってしまっている状況でした。例えば、課金まわりの処理や、MA系の処理、会員ステータスの変更処理などです。
また、倉庫連携処理はエアークローゼットで絶対に止まってはいけないシステムトップ3に入るほど重要な機能ですが、他の機能のエラーの影響で止まってしまうこともたびたび発生していたため、倉庫だけに特化させて影響がない状態にしたい事情もあり、新規でシステムを切り出すことにしました。
⑩stylingWebの切り離し(2018/02 〜 2018/09)
こちらは、倉庫連携処理と並んでairClosetで絶対に止まっていけない機能トップスリーに入る、スタイリング機能になります。これまでは、②の管理Webの中に含まれていたのを、別環境に切り出したのがここの改善です。
AngularJSからReactへ
この頃にはAngularはかなりシェアを落としており、かつ使っているバージョンは1.5で、2移行のAngularは全く別のフレームワークのためアップグレードの選択肢はありませんでした。
また、この機能はかなりパフォーマンスも求められる機能になるため、AngularよりもReactの方が適していると考えたことも理由のひとつです。
ちなみにAngularJSの頃のスタイリング機能では、パフォーマンスチューニングのために一部jQueryでDOM操作を行い、情報管理をAngularに任せるような変態実装をしていました笑
Node.js - fastify
フロントエンドをReactにした一方で、バックエンドはfastifyを採用しました。理由は明確で圧倒的なパフォーマンスの良さです。通常フレームワークを入れると素の実装よりも多少レイテンシーが発生するのが一般的ですが、fasitifyはどんな実装になっているのか、Node.jsで3rdパーティに依存せずにhttp serverをたてるよりもさらに高いパフォーマンスを実現しています。
また、多くのNode.jsフレームワークの例にもれず、かなり軽量で自由度の高いフレームワークなので、そのあたりも好みのポイントです。
⑪airClosetAppのreplace(2018/05 〜 2018/12)
⑧で書いたように、React Nativeに明るいユタマこたろう(YutamaKotaro)がいたことと、ここだけswiftで開発しないといけない状態であったこと、そして大々的なUIリニューアルを行いたい3つの理由が重なり、airClosetのNativeアプリをこのタイミングでreplaceしています。
ここでは当然迷うことなくReact Nativeを選択しており、もはや既定路線となっていました。
⑫倉庫連携システムreplace(2019/06 〜 2019/09)
⑨にも倉庫連携システムのreplaceがありましたが、なんとビジネス上の理由によりここでまた倉庫移転を行っています。システム伴わないものを含めると3年連続で倉庫移転しているので、毎年の恒例行事のようになっていました笑(ちなみに2020年12月現在は移転しておりません)
それに伴ってまた倉庫管理システムが別のものに切り替わったため、こちら側のシステムもまた新規に構築しています。
Node.js - fastify
このシステムもNode.jsのフレームワークにはfastifyを採用しています。理由は⑪に書いたものと同様です。
typescript
このあたりから新規で開発するものはtypescriptで開発するようになってきています。既存の環境ではまず使えるようにして、そこに新規で載せるものはtsで書くような形をとっています。
typescriptを採用したのはやはりサービスが大きくなってきた中で、あらためて型でアプリケーションを堅牢にしたいニーズが高まってきたためです。
また以前はbabelを使っていましたが、素のNode.jsがbabelで担保していたecmaScriptの仕様をだいぶカバーしてきており、babel自体もしだいにつかわれないようになってきていたので、2018年頃にはエアークローゼットではbabelは外していく流れになっていました。
⑬倉庫管理システム新規開発(2019/06 〜 2019/09)
⑫と同様のタイミングで、これまで他社の倉庫管理システムに依存していた機能を内製で開発しています。具体的にはアパレル業界で"ささげ"と呼ばれるアイテムの入庫に伴う処理と、レンタルしていたアイテムの返却処理機能です。(ちなみに"ささげ"は撮影・採寸・原稿のことだそうです)
kotlinでのAndroidアプリ開発
あまり詳しくは書けませんがハードウェアを絡めた処理を行っており、そのために業務用にAndroidアプリを開発する必要がありました。
ReactNativeも当然選択肢としては考えましたが、開発要件的に結局Native層の開発が必須になるため、ここではkotlinでの開発を選択しています。
React, Node.js - fastify
Webの管理画面には⑩、⑫と同様にReact, fastifyを用いた構成をとっています。もはやそれが慣れてて一番はやいというのが圧倒的に大きい理由ですね笑
postgreSQL
ここまでDBには触れてませんでしたが、ここまでは基本全てMySQLを使っていました。あえてそれを崩してpostgresを入れたのはスキーマ管理が可能であることなどデータベースとしての機能が豊富であることと、かつもともと懸念していたパフォーマンスの問題は最近ではクリアされてる印象だったためです。
ちなみにとりあえず使ってみっかと思って使ってみた結果、今現在だとMySQLで良かったと思っているのが正直なところです笑
その理由は、いくら高機能でもアプリケーションで使うときはORMを使う以上、ほぼ何も変わらないのと、データ解析もデータウェアハウスに流してそっちでやっているので、エアークローゼットではそれも必要がない。またこれまで使っていたツールまわりがpostgresに対応していなかったり、DDLが結構異なるためにMySQLで使ってたスニペットがそのままだと動作しなかったりがあったためです。
⑭airClosetMall新規開発(2019/07 〜 2019/10)
今年の4月に正式ローンチしたairCloset Mallのベータ版をこの時期に開発しています。
React, Node.js - express
ここの開発はかなり社外のエンジニアの手も借りたものの、ソースを見ればすぐわかる状態にはしたかったので、エアークローゼットの多くのシステムと同じ構成をとっています。
go
airCloset Mallも実際にものを届けるサービスのため、倉庫との連携が必須なサービスです。ユーザ側のシステムはNode.js - Reactで構築した一方で、そういった裏側の処理についてはgoで構築してます。が、正直迷ったところです。
最終的にメリットとして考えたポイントは、今後の選択肢とのひとつとしてgoを持っておきたかった点、goで開発していること自体が技術的なブランディングにつながる点、担当エンジニアのテンションが上がる点です。
後の2つはあまり本質的ではないと思いつつ、まあでもたまには違う空気も吸ってみたかったというところでしょうか。
⑮ID連携機能新規開発(2020/05 〜 2020/10)
エアークローゼットではairCloset, airCloset Fitting(pickss),airCloset Mallと複数事業展開しているわけですが、とくにairClosetとairCloset Fittingがサービス内容も近く、お客様から見ても共通で持ちたい情報が多いです。そのためまずは共通のIDでログインができ、一部メタ情報も共通で管理してくれる基盤をマイクロサービスとしてここで開発しました。
typescript - express
最近ではもはやtypescriptベースのフレームワークや、ORMまで出てきています。エアークローゼットもtypescriptを全面的に使ってきているので、その流れに乗らん理由はないってことで、ここまでとくにORMまでは触れてませんでしたが、ここではtypeORMを採用してたりもしてます。
redisのPub / Sub
それぞれのサービスで持っていたデータ(例えば氏名や住所など)をID連携サービスのDBでマスタ管理するようになったわけなんですが、そのデータを使っている参照を全てアップデートしようとすると多大なコストがかかることが見込まれていました。
例えばそのデータはお客様向けのAPIだけでなく、管理画面でスタイリストが見るためにデータをとってきていたりなどが数多くあったためです。
そのためそれぞれのサービスの参照先はこれまでどおりそれぞれのサービスのDBに向けつつ、ID連携サービスのDBにデータの更新が入るタイミングでその情報をpublish。それぞれのサービスがそれをsubscribeしているので、そのタイミングでデータを取得してそれぞれのDBも更新といった形で同期をとっています。図解すると下記のような感じ。DBが直接publishしたりsubscribeしたりしてる図に見えますが、もちろんそれぞれ間にアプリケーション入ってます。
今抱えている課題
大体これまでの経緯はそんなところです。それぞれのポイントでの技術選定自体はまあそんなもんかなと思いつつ、今抱えている課題としては、まずよくある話として息の長いシステムで技術的負債が溜まってしまっていること。それからサービスごとに特化してシステムを開発してきているために、事業の横展開に弱いことです。
例えばわかりやすいところだと、airClosetでもairCloset Fittingでもスタイリストがお客様の要望を元にスタイリングを行うって要件がありますが、それぞれのサービスに特化してしまっており、今だと似て非なるものを開発しなければならない状態です。
これから
そのためこれからやっていきたいことはドメインを事業単位ではなく、事業の枠を超えた機能単位で考え、それをマイクロサービスとして切り出し抽象化していきたいと考えています。
また組織としても事業単位ではなく機能単位で分けているので、その実態に合わせたシステムも変えていこうかなと思っている次第です。
またそれを進めていけば自然と古いシステムの新陳代謝も測れるので一石二鳥ですね!
最後に
最後まで読んでいただきありがとうございます。
インフラの話やライブラリレベルの話、それから具体的な機能実装の際の設計のトレードオフ等には触れていません。まだここで書いていないシステムもかなり多くあります!もっとそこまで掘り下げて聞きたい方がいらっしゃいましたら、まずはカジュアルにお話しできればと思いますので「話を聞きに行きたい」からご連絡をお待ちしております。