Slide 1

Slide 1 text

DRFを少しずつ オニオンアーキテクチャに寄せていく NEALLE 2025.2.22 株式会社ニーリー 野呂 有我

Slide 2

Slide 2 text

2 氏名 所属 経歴 野呂 有我 / Yuga NORO 株式会社ニーリー プラットフォーム本部 アーキテクチャチーム ・大学院時代に友人と楽譜販売サービスを立ち上げ ・その後、SIer企業に参画 ・副業としてニーリーでいくつかの開発に携わる ・フリーランスを経て、ニーリーへ 1|自己紹介

Slide 3

Slide 3 text

目次 1|自己紹介 2|プロダクト紹介 3|DRFについて 4|起こった問題 5|意思決定 3 6| 振り返り 7| これからのこと

Slide 4

Slide 4 text

4 2|プロダクト紹介

Slide 5

Slide 5 text

5 3|Django DRFについて DRFは、超高速開発を可能にするPythonのWeb Framework Djangoのプラグインで、 View/Serializer/Modelの3つのパーツを組み合わせて、一瞬でAPIを構築できる 認証やユーザー管理、ファイルのアップロードに至るまで基本的には全て組込済み

Slide 6

Slide 6 text

6 弊社もその高速開発を利用し、機能をどんどん作り 急激なグロースを実現 ● ・プロダクト開発人数が当初の 2人から20人以上にまで増加 ● ・顧客も増え続け、機能開発のさらなる加速が必要になった 3|DRFについて

Slide 7

Slide 7 text

7 ・スタートアップは最初からそのサービスが成功するかどうかを知る術はない! ・できる限り少ないコストで、できるだけ早くサービスを、機能をリリースし続け、  結果として生き残ったサービスだけが「その先」を知ることができる! ・ 結果として「技術的な借入」が沢山ある状態に ・「借入」は「利息」を生み、開発速度が段々遅くなっていく 3|DRFについて

Slide 8

Slide 8 text

8 ・今あるコードベースを捨て、別の言語・別のFWに移行する ・今あるコードベースを少しずつ改善していく 我々は後者を選択した! こうなった時、取れる選択肢は2つ 3|DRFについて

Slide 9

Slide 9 text

9 ・開発を止めたくなかった(止められなかった)  → 移行中は機能開発が止まってしまう ・移行にかかるリソースも開発に回したかった  → 開発アジェンダは増えるばかり ・性能的な面などで問題が起こっているわけではなかった  → Python/Django/DRFに問題があるわけではない! 3|DRFについて

Slide 10

Slide 10 text

10 4|起こった問題 では、その時どんな問題があったか? 1. 依存関係の複雑化 2. 業務ロジックの分散と技術的関心との密結合 3. キャッチアップ難度の増加

Slide 11

Slide 11 text

11 1. 依存関係の複雑化 4|起こった問題

Slide 12

Slide 12 text

12 4|起こった問題

Slide 13

Slide 13 text

13 1. 依存関係の複雑化 4|起こった問題

Slide 14

Slide 14 text

14 1. 依存関係の複雑化 4|起こった問題

Slide 15

Slide 15 text

15 1. 依存関係の複雑化 4|起こった問題

Slide 16

Slide 16 text

16 1. 依存関係の複雑化 どこを触っても全範囲に影響がある!!! 4|起こった問題

Slide 17

Slide 17 text

17 1. 依存関係の複雑化 ・影響範囲が読みきれず、本来は同じロジックを変更すれば良いものを、 コピーして別の場所に作り直す、ということが常態化 ・結果として、ほぼ同じことをやっている関数が大量に発生 ・ほぼ同じ画面の権限違いなどのために3重実装が行われる などが横行した 4|起こった問題

Slide 18

Slide 18 text

18 1. 依存関係の複雑化 さらに... ・プロジェクトを構成するアプリケーション(App)が 複数あるが、それらのほぼ全てが別のアプリケーションに 直接依存! ・関数もクラスもORMのModelもインポートし、  DBの値も 別のAppから書き換えている状態だった 4|起こった問題

Slide 19

Slide 19 text

19 2. 業務ロジックの分散と技術的関心との密結合 4|起こった問題

Slide 20

Slide 20 text

20 2. 業務ロジックの分散と技術的関心との密結合 4|起こった問題

Slide 21

Slide 21 text

21 2. 業務ロジックの分散と技術的関心との密結合 全ての層に業務ロジックが書かれている!!! 4|起こった問題

Slide 22

Slide 22 text

22 2. 業務ロジックの分散と技術的関心との密結合 4|起こった問題

Slide 23

Slide 23 text

23 2. 業務ロジックの分散と技術的関心との密結合 さらに、全ての層で永続化も行われている!!!!! 4|起こった問題

Slide 24

Slide 24 text

24 2. 業務ロジックの分散と技術的関心との密結合 ・自動テストは書かれていたが、全て実際のDBを使った統合テストに なっていた(ならざるを得なかった) ・DBの状態遷移が業務ロジックに含まれているため、影響範囲の特定が  非常に困難 ・ViewやSerializerに書かれた業務ロジックは、Viewの機能やSerializerの  機能と分離できないため、ロジック単体での再利用が不可能 4|起こった問題

Slide 25

Slide 25 text

25 2. 業務ロジックの分散と技術的関心との密結合 結果、ロジックを持ったViewやSerializerが大量に継承される ・自動テストは書かれていたが、全て実際のDBを使った統合テストに なっていた(ならざるを得なかった) ・DBの状態遷移が業務ロジックに含まれているため、影響範囲の特定が  非常に困難 ・ViewやSerializerに書かれた業務ロジックは、Viewの機能やSerializerの  機能と分離できないため、ロジック単体での再利用が不可能 4|起こった問題

Slide 26

Slide 26 text

26 3. キャッチアップ難度の増加 4|起こった問題

Slide 27

Slide 27 text

27 3. キャッチアップ難度の増加 ・…のような状態になったコードはキャッチアップコストが非常に高く、  技術者の参入難易度が増加した ・それでも平然と開発し、大きな障害も特に出さず、  変更障害率も低かったのは、本当にすごいと思う ・ただ、それでもコア領域の開発はかなり時間がかかるようになっており、  1項目のDBへの追加で3日などの工数がかかるまでになっていた (フロントエンドも含む) 4|起こった問題

Slide 28

Slide 28 text

28 4|起こった問題

Slide 29

Slide 29 text

29 5|意思決定 意思決定 ・ある日、決済会計領域の大規模な改修が決定 ・そこで今ある問題↓をその領域に持ち込まないためにどうすべきかを考えた 1. 依存関係の複雑化 2. 業務ロジックの分散と技術的関心との密結合 3. キャッチアップ難度の増加

Slide 30

Slide 30 text

30 意思決定 依存関係の複雑化を食い止めるため以下のルールを策定 1. 別Appの関数への直接依存の禁止 2. 別Appのテーブルへの直接の書き込みの禁止 3. View/SerializerからDBへのアクセスを禁止 4. SerializerはViewからのみ依存して良い 5. ViewはUrl.pyからのみ依存して良い 5|意思決定

Slide 31

Slide 31 text

31 意思決定 については、多分特に疑問はないはず 1. 別Appの関数への直接依存の禁止 2. 別Appのテーブルへの直接の書き込みの禁止 3. View/SerializerからDBへのアクセスを禁止 4. SerializerはViewからのみ依存して良い 5. ViewはUrl.pyからのみ依存して良い 5|意思決定

Slide 32

Slide 32 text

32 意思決定 この「直接」については後からお話しします 1. 別Appの関数への直接依存の禁止 2. 別Appのテーブルへの直接の書き込みの禁止 3. View/SerializerからDBへのアクセスを禁止 4. SerializerはViewからのみ依存して良い 5. ViewはUrl.pyからのみ依存して良い 5|意思決定

Slide 33

Slide 33 text

33 意思決定 業務ロジックの分散と技術的関心との密結合を食い止めるため 1. View/Serializer/Modelへの業務ロジック記載を禁止 2. Usecase層という、業務フローを組み立てる層を追加 3. Domain層という、業務ロジックを記載する層を追加 4. Domain層からDBへの書き込みを禁止 5. DBの読み書きが許される Infrastructure層を追加 5|意思決定

Slide 34

Slide 34 text

34 意思決定 これにより、各レイヤーの分担と依存の方向は以下のように 5|意思決定

Slide 35

Slide 35 text

35 意思決定 これにより、各レイヤーの分担と依存の方向は以下のように 5|意思決定

Slide 36

Slide 36 text

36 意思決定 そう、これは一般的なオニオンアーキテクチャー 5|意思決定

Slide 37

Slide 37 text

37 意思決定 そう、これは一般的なオニオンアーキテクチャー これを実現するために、 APIViewとserializers.Serializer以外の使用を断念😭 5|意思決定

Slide 38

Slide 38 text

38 意思決定 そう、これは一般的なオニオンアーキテクチャー これを実現するために、 InjectorというDIコンテナ(のようなもの)を利用 https://github.com/python-injector/injector 5|意思決定

Slide 39

Slide 39 text

39 意思決定 一般的なオニオンアーキテクチャになったため、 新規参画者にも「この領域はオニオンアーキテクチャです」 と言えば大体伝わるようになり、 参画ハードルもグッと下がった! 5|意思決定

Slide 40

Slide 40 text

40 意思決定 一般的なオニオンアーキテクチャになったため、 新規参画者にも「この領域はオニオンアーキテクチャです」 と言えば大体伝わるようになり、 参画ハードルもグッと下がった! …が 5|意思決定

Slide 41

Slide 41 text

41 意思決定 ・今オニオンアーキテクチャ化しているのは  この青い部分だけ ・その部分については見通しもよくなり、  参画ハードルも下がっていると信じている ・だが未だそうなっていない箇所の方が多い! apps/ ├── __init__.py ├── __pycache__ ├── business_crosscuing ├── cash_selement_common ├── client_analytics ├── client_manuals ├── core ├── core_system_link ├── coupon_page ├── customers ├── digital_cash_results ├── digital_cash_schedules ├── guarantees ├── libs ├── mypage ├── parkings ├── payments ├── platform ├── reservation_and_approval ├── selements └── users 5|意思決定

Slide 42

Slide 42 text

42 意思決定 ↓再掲 5|意思決定

Slide 43

Slide 43 text

43 意思決定 ・この問題があると、いくらApp1つ単位で依存関係を整理しても、  結局外からDBの値を書き換えられてしまう ・そこで、さらに「Internal API層」を定義  ・これはマイクロサービスであればRPC(Httpなど)に置き換わっているはずの部分 5|意思決定

Slide 44

Slide 44 text

44 意思決定 5|意思決定

Slide 45

Slide 45 text

45 意思決定 5|意思決定

Slide 46

Slide 46 text

46 意思決定 5|意思決定

Slide 47

Slide 47 text

47 6|振り返りと現状の整理 結果、どうだったか?

Slide 48

Slide 48 text

48 6|振り返りと現状の整理 導入中 ・DRFの持っている便利機能を大部分捨てる判断のため、  最初はメンバーの反応が気になった ・最初のAppへの導入中は、書く量の増加が目につき不安だった ・最初はもっと厳格にオニオンアーキテクチャを  導入する予定だったが、  必要性の薄そうな部分を少しずつ削って柔軟にした   ・この判断も実は少し不安だった

Slide 49

Slide 49 text

49 6|振り返りと現状の整理 導入後 ・最初の導入プロジェクトに参加してくれたメンバーの反応は上々  だった(と思う) ・逆に考えることが減る ・レイヤーが増えることで変更がしやすくなる ・凝集度が高くなるため影響範囲の特定がとにかく簡単 ・というより、層ごとに単体テストがあるので、  影響範囲は勝手に特定される

Slide 50

Slide 50 text

50 6|振り返りと現状の整理 現時点での所感 ・この形がベストかはわからないが、既存の資産を捨てず、開発速  度も落とさずに(部分的にではるが)問題を解決できた ・もし、同じような課題を抱えている方や、  今後抱える方の問題解決の参考にしていただけたら幸い

Slide 51

Slide 51 text

51 これからのこと ・新しいApp領域を作成する場合にどんな規範に沿うか、  どんなアーキテクチャを採用するかは概ね決まった ・しかし、実際にはまだ最初に挙げた状態のままのAppが  沢山あり、そしてそれらの領域は大抵コア業務ドメイン ・ここから、まだ奔放な状態のAppについても  オニオンに寄せていく予定 7|これからのこと

Slide 52

Slide 52 text

ニーリーではプロダクトエンジニア、 その他のポジションも積極採用中です! https://jobs.nealle.com/ We are hiring!!!

Slide 53

Slide 53 text

Thank you 53