8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

肥大化したパッケージを爆殺する

Last updated at Posted at 2022-07-12

概要

友達と開発しているChrome拡張の設計話です。

Chrome拡張は、以下の2つの構成で成り立っています。

  • 特定のウェブページのコンテキストで実行されるcontents script
  • Webページ上に記述されたスクリプトをWebブラウザに組み込み、ページを離れた後も実行できるservice worker

このcontents scriptにUI層の処理、ドメイン層の処理が混在して肥大化していました。
また、utilsフォルダに色んなものが詰め込まれていたりしていました。
これらをドメイン駆動設計(DDD)をもとに肥大化したパッケージを爆殺させて(リファクタリングして)、責務がわかりやすいコードにしました。

Chrome拡張の紹介

MokurenというGitHub上でIssueやPullRequestをサイドバーで開けるChome拡張機能を開発しています。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3438363534342f36326133313134632d306638302d623262662d646230322d3232373663636133376133332e676966.gif

Mokurenについては以下をご覧ください。
友達と個人開発したChrome拡張が便利すぎた

パッケージの肥大化という課題

先にも述べたように以前のMokurenはパッケージが肥大化しているという課題がありました。
具体的には以下のようなフォルダ構成になっていました。
※ Mokurenは、Vue.js + TypeScriptを使用しております

Before

src
  |-apis
  |
  |-contents_script
  |  |-detail
  |  |  |-*.vue   // UI
  |  |-detail.ts  // サイドバーを開く処理とGitHubのIssueの処理
  |  |-index.ts   // contents_scriptのメイン処理
  |  |-pr.ts      // GitHubのPRの処理
  |
  |-components
  |  |-*.vue  // UIコンポーネント
  |
  |-models
  |  |-*.ts  // GitHubやMokurenのモデルクラス
  |
  |-store
  |  |-*.ts  // store(状態管理)
  |
  |-style
  |  |-*.scss  // SCSS(CSS定義)
  |
  |-utils
  |  |-*.ts  // ごちゃ混ぜの色んな処理がたくさん
  |
  |-App.vue
  |--background.ts  // service workerの処理(バックグランド処理)
  |--main.ts        // Vueインスタンスの作成処理
  |--manifest.json  // Chrome拡張の設定ファイル

以下のような パッケージ肥大化の問題があり、どこに何の処理があるか分かりづらい状況です。

  • contents scriptパッケージ内に「UI層の処理」と「ドメイン層の処理」が混在している
  • componentsパッケージにドメインに関する処理がある
  • utilsパッケージに色んなものが詰め込まれている
  • src/contents_script/details.tsの中に「サイドバーを開く処理」と「GitHubのIssueの処理」の二つの処理がある
  • modelパッケージには、GitHubのモデルとMokurenのモデルの両方が並列に置かれている

設計

上記の課題を認識し、一緒に開発している友達とクリーンアーキテクチャやドメイン駆動設計を勉強し直しました。
よりDDDらしい設計でリファクタリングを行うことに決めました。
リファクタリングを行なって、下記のフォルダ構成に至るまでに以下のことを行いました。

  • ユースケースの洗い出し
  • UIとロジックの分離
  • utilsフォルダを爆殺

After

src
  |-background
  |  |-index.ts  // service workerの処理(バックグランド処理)
  |
  |-contents_script
  |  |-index.ts  // contents scriptの処理 (コントローラーを呼び出すだけ)
  |
  |-domain
  |  |-github
  |  |  |-model
  |  |  |-client  // GitHubに関するAPIインターフェース や GitHubのDOM操作インターフェース
  |  |-mokuren
  |     |-model
  |     |-client      // モクレンに関するAPIインターフェース   
  |     |-repository  // モクレンに関する永続化処理インターフェース        
  |
  |-infrastructure
  |  |-client      // domain層で定義されたAPIインターフェースの実体
  |  |-repository  // domain層で定義された永続化処理インターフェースの実体
  |  |-store       // store(状態管理)
  |
  |-ui
  |  |-components_creator  // DOMにUIコンポーネントを挿入するクラス
  |  |  |-*.ts
  |  |-components  // UIコンポーネント
  |  |  |-*.vue
  |  |-page        // UIページ
  |  |  |-*.vue
  |  |-style
  |     |-*.scss   // SCSS(CSS定義)
  |
  |-usecase
  |  |-*.ts  // ユースケース処理
  |
  |-config   // DIコンテナ設定
  |  
  |-manifest.json  // Chrome拡張の設定ファイル

ユースケースの洗い出し

ユーザーとソフトウェアの間の相互関係を起こすアクションを定義しました。
実際に文章にして具体化してみると、どのようなモデルを作ればいいのかが分かってきます。
また、ユースケースごとに開発が進められるため、ユースケース層を見れば開発状況を把握することが可能となりました。

mokurenでは、以下のようなユースケースになりました。(他にもありますが、一部のみ抜粋しています)
ここで挙げたユースケースがそのままユースケース層の処理となります。

utilsフォルダを爆殺

utilsフォルダは名前の通り「役に立つもの」みたいところで、とりあえずここに入れとけば間違いないみたいな状態になりがちです。
そうするとutilsパッケージは肥大化してきてしまいます。
今回のリファクタリングでutilsフォルダを廃止して、適切な場所へ配置しました。
どこか分からないものについては、新規にパッケージを作ったりしてパッケージを見て何に関する処理か分かることを目指しました。

UIとロジックの分離

クリーンアーキテクチャやDDDのよくある理想系は以下の図になります。
自分たちもこの依存関係を参考に実装に落とし込みました。

スクリーンショット 2022-07-09 18.58.12.png

Mokurenの一部の機能のみ以下に図示します。

UI→UseCase
components(UI層)からは、クリックした時にUseCaseを呼ぶのみのロジックしか持ちません。

UseCase→Domain
ドメインの処理を組み合わせてユーザーのユースケースの挙動を実装します。

Infrastructure→Domain
InfrastructureからDomainへの依存は、Client(APIインターフェースなど)やRepository(永続化処理)のinterfaceを継承しているのみです。

例外
分かりづらいかもしれませんが、基本的には依存関係を上図を意識していますが、一部例外を作っています。
それは、UseCase層がcomponents_creator(UI層)を呼び出すことです。

components_creator(DOMにVueコンポーネンツを埋め込むパッケージ)はUI層に置いています。MokurenはChrome拡張です。なので、どうしてもDOMにUIを直接埋め込むという処理をしなければなりません。
UseCase層にinterfaceを作り依存関係逆転させることも考えましたが、冗長になりコードが分かりづらくなるデメリットを天秤にとった結果、UseCase層がUI層を依存することを許容することに決めました。


UI層には、Domainのロジック(業務知識など)入れず、Domain層を開発の中心にすえ、コードやコミュニケーションを常にDomainモデルと一体化させました。
このようなモデルがどのような振る舞いをするのか、仕様変更時にどう変わるのか。常に最新のより表現力の高いモデルを追求し、コードを追従させていくことにより、MokurenのDomainの理解を深め、Mokurenの価値を追求できるようになりました。

まとめ

今回はChrome拡張にDDDの考え方を適用して設計を行うことで、肥大化したパッケージを爆殺しました。
以前に増して、開発しやすくなったと実感しています。
他にも単体テストやE2Eテストの作成や、StoreとRepositoryの連携など試行錯誤しながら開発を行っています。

Mokurenの価値(コア)と向き合いながら、毎週機能開発を進めてアップデートしております。
そんな素晴らしい拡張機能を是非インストールしてみてください!
ログインや初期設定などは要りません!ストアからダウンロードしてすぐに使えます!便利です!

MokurenはUI/UXにもこだわっています。気になった人は以下noteも見てみてください。

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?