2019年振り返り
前職の振り返り含むので何だかんだ1年半の振り返り。
2019年
やったこと
- 婚約
- 退職&開業
- iOS Frontend開発
- Web Frontend開発
- Web Frontendのトレーナー
- 技術書典
向き合った細かいトピックなど
Web Frontend
-
- ふつうの自動化
- ふつうのナビゲーション整理
- ふつうのMVVM
- ふつうの最適化
- Background Transferの検証
他
他にも細かいものは沢山あるがある程度取り組んだもののみ。 思い出したら追加します。
OSS
総括
フリーランス開業とか技術書典でバタバタして色々半端な状態。 今まで気になった周辺技術を調べて深堀りしてたらそこそこ積み上がってたみたいな感じの学び方だったけどそろそろ逆算して計画的に進めないと厳しい。
フリーになってやることはそこまで変わってないけど求められるコードの品質は下がったとは思う。
2020年
やりたいこと
- 結婚
- します
- 法人化
- 多分した方がお得
- アルゴリズム、プロコン
- 業務でも使ったりする
- 取り敢えず水色が目標
- TaPLの理解
- 70%理解してます。くらいは言えるように。
- 言語化の習慣、アウトプット
- バックエンド業務
- デザインシステムの成果物(パターンライブラリなど)の本
- 技術書典で半端なものを出してしまった反省
- 2Dゲーム制作(趣味)
- unity楽しい
- ML
- ツールを扱えるレベル
優先度順。英語と言いたいところだけどキャパオーバーなので除外。 特にインプット/アウトプットやプログラミングのトレーニングは習慣化しないと厳しい。
DIの目的とメリットについて
今日はDependency Injection(以下DI)の目的を整理しました。 できるだけ目的やメリットをベースにまとめていきます。
tl:dr
- DIはオブジェクトを外から渡すこと → モジュールは依存するオブジェクトの依存解決(生成)方法を意識しない
- 抽象に依存することにより疎結合に → モジュールは依存するオブジェクトの実装の方法を意識しない
- 2に静的解析が組み合わさると大変便利
依存するオブジェクトの参照を解決する方法
DIの目的は特定のモジュールの振る舞いと依存解決の方法を分けることです。 今回は例としてapiサーバーにアクセスするためのクライアントクラス(以下APIClient)を実装します。 APIClientは内部でhttp通信を行うためのクラスを参照する必要があるものとします。
1. 内部で生成する
export class APIClient { httpClient: HTTPClient; constructor() { this.httpClient = new HTTPClient(baseURL: "https://example.com"); } request(config) { this.httpClient.request(config) } }
内部で必要なプロパティを生成する方法です。APIClientの振る舞いを変更する方法は内部の実装を変える必要がある他、
HTTPClient
のConstructorに変更があった場合に、APIClientの実装を変更する必要があります。
2. (Static)Factoryパターンを使って取得する
export class APIClient { httpClient: HTTPClient; constructor() { this.httpClient = HTTPClientFactory.create(); } } export class HTTPClientFactory { static httpClient: HTTPClient static setInstance(httpClient: HTTPClient) { this.httpClient = httpClient; } static getInstance() { if (!!this.httpClient) { return this.httpClient; } return this.httpClient; } }
Factoryパターンを用いることで、APIClientの実装とHTTPClient
の生成を切り離すことに成功しました。
HTTPClient
の生成に変更があった場合もAPIClientに変更を加える必要はありません。
実装の切り替えはFactoryクラスのgetter, setter経由で行います。
ただしこのコードにはいくつかの問題があります。
- グローバルにインスタンスを保持しているため、どこからでも書き換えられる
- モジュール内部で依存解決を行なっているため、実装を見ないと依存関係がわからない
- Factoryクラスへの依存が発生する
3. DI(Consturcutor Injection)を使う
export class APIClient { constructor(private client: HTTPClient) {} }
上記はConstructor経由でオブジェクトを渡すConstructor Injectionと呼ばれます。 APIClientは渡されるオブジェクトを使用するだけなので、依存解決の方法や依存オブジェクトの生成方法を意識する必要がありません。 また、依存関係はConstructorに全て宣言されているため、依存解決を検証しやすいというメリットがあります。
4. DI(Lazy Injection)を使う
export class APIClient { setClient(client: HTTPClient) { this.httpClient = client } }
依存オブジェクトが得られるタイミングがモジュールの生成タイミングと異なるケースや、後から実装を差し替えたいケースがあります。 このような場合にはsetter経由で依存オブジェクトを渡します。
この場合生成時にパラメータが初期化されているか分からないので、あくまでConstructor Injectionを実装した上で必要な場合に実装するのが良いです。
DIと抽象化プログラミング
APIClientの依存する対象はHTTPClient
とは限りません、典型的な例で言えばテストの場合、実際にHTTP通信を行って
データを返却する必要はありません。そのため、HTTPClient
の振る舞いはそのままに実装を変えたいケースがあります。
以下のコードではHTTPClientの振る舞いと実装を分割しています。
interface APIBackend { request(config) } class HTTPClient: APIBackend { request(config) { ... } } class MockClient: APIBackEnd { request(config) { ... } } export class APIClient { client: APIBackend; constructor(private client: APIBackend) { } }
上記のようにAPIClientが依存する機能をAPIBackend
として定義することで、APIClientが依存するオブジェクトを容易に変更できます。
APIClientは自身が必要な機能だけを意識して実装するため、実際に渡される依存オブジェクトとは疎結合になります。
つまり、APIClientのテストを書く場合、APIClientで書いているロジックのみをテストすれば良いことになります。
DIと静的解析
静的解析は必ずしも必要なわけではありませんが、実行前に依存解決の検証ができるので、安全にプログラミングができます。
依存対象に変更があった場合、影響するモジュールは容易に判別可能ですし、いわゆるnull許容のような型の解析をサポートしている言語では 依存するオブジェクトが渡されているタイミングも示すことが可能であるため、開発時にコードから様々な情報を得ることができます。
以下の例ではclientインスタンスはモジュール生成タイミングで必ず渡されているので安全に使用できますが、
authToken
は生成タイミングでは存在しないため、内部でも気をつけて取り扱う必要があることがわかります。
export class APIClient { authToken: string? constructor(private client: APIBackend) { } setToken(authToken: string) { this.authToken = authToken; } }
よく混同されがちなDI Containerの話
DIを用いることでそれぞれのモジュールは疎結合になりますが、実際にはそれぞれの依存を解決するレイヤーが必要になります。 DIはデザインパターンであって、依存グラフを解決する仕組みではありません。そこで、それらを解決する仕組みの一つがDI コンテナです。 詳しくは検索すれば良い記事が沢山転がっていますのでそちらをどうぞ。
まとめ
DIの目的について順番に解説しました。実際の現場では抽象化や静的解析と組み合わせて使用されることがほとんどですが、 あくまで各モジュールを疎結合に保つためのデザインパターンなので、言語によらず意識的に実践することで結果的に全体の設計が綺麗になっていくかと思います。 対象となるスコープも小さいので導入も簡単ですね。
技術書典5にサークル参加しました その2
前回はサークル参加の反省をメインにまとめましたが、今回はイベント自体の感想を一般参加者目線のまとめになります。
戦利品
一人サークル参加してしまったため、半ば諦めていたのですが隣のサークルの方のご好意で回ることができました。ありがとうございました!
時間は15:00頃で本は売り切れているところも多かったですが、DLカードをメインで狙っていたので全く問題なかったです。以下戦利品です(あまり買えなかった)。
一周だけ回って気になるものを買うという感じだったのであまり量は買えませんでした...。 あとで買っておけばと後悔したものも沢山あるのですがBooth版などを期待したいと思います。
ちなみにこちらは販売している際に、とあるお客様が「UIに携わるものとしてこういった活動をしてくれる方に感謝している」とくださったものです。こちらこそとても励みになりました。ありがとうございます。
知らない技術に出会える場
今回特に参加してよかったなと思ったのは知らない技術に出会えるところですね。本当に色々な技術領域の方が参加しているので、まったく触れることのなかった技術に触れるきっかけになります。
「水晶雫世界」さんが頒布されていたCrystalDiskInfoの開発秘話本ですが、僕が不勉強なのもあり名前も知りませんでした。WindowsのSSD/HDDモニタリングといえばコレというほどデファクトなOSSだそうです。知らなかったものの普段Webばかりの自分にとってはSSD/HDDのモニタリングツールというワードには惹かれるものがあり、購入しました。受け身で知らない技術に出会えるのは嬉しいですね。
「技術季報」は去年売る側だったのですが、今回は買う側でした。正直パンフレットかなくらいの認識だったのですが「サークルの自動配置」などの技術記事が書いてあったりと技術書として楽しめました。
暗号通貨の分野にも興味があったので「NEO」に関する書籍を購入したのですがこちらはDLカードを無くしてしまいました...。しかし、購入した際、月一で勉強会を開いているという情報をサークルの方から頂いたので参加してみようかなと考えています。
まとめ
今回はサークルとしても一般としても参加できたのですごく楽しかったです。こういったイベントを支えてくれるスタッフ、サークルの皆さんには感謝しかないです。次回開催時も参加するつもりなので皆さんよろしくおねがいします。
技術書典5にサークル参加しました その1
頒布したもの
「本 + PDFダウンロードカード セット」で500円で頒布しました。
用意したのは以下。
- 本は100部
- PDFダウンロードカード100枚 (+予備94枚)
※ ダウンロードカード6枚は手違いでダメにしてしまいました
結果
詳しく時間を見ていないのですが12:30頃に本は完売してホッとしていました。 その後もダウンロードカードのみで購入していただき最終的には残り8枚でした。
- 本+PDFダウンロードカード: 100セット完売
- PDFダウンロードカード88枚
でした。予備のカードまで割と買っていただけてかなり嬉しかったです。 とにかく安心しました。
なぜデザインシステムをテーマにしたか
Web、iOSのフロントエンドエンジニアとして働いていくなかで、かねてからUIの共通化やコンポーネント化は開発効率だけを目的にするものではないし、UIコンポーネント=正義というどちらかというとエンジニア目線の押し付けはデザイナーにとってもユーザーにとっても嬉しくない、と思っていたのでデザインシステムはそのあたりの話をするのにちょうどよい、ということでこのテーマでの執筆を決めました。端的にいうと次のようなことを話したかったのです。
執筆の反省
計画もなく取り敢えず書く。といった感じだったのでギリギリになって知らないことが増えてきて焦りだすわけです。印刷所について調べることもないので当然デッドラインなども知らないわけです。なんとかなるだろうと思って書いていました。当たり前ですが締切を事前に調べておき、マストで必要なものを洗い出し、それからじっくり書き始めるのが良かったかと思います。
以下大きなしくじりです。
- 印刷は一部カラーにする予定が締切に間に合わず、モノクロに
- PDFダウンロードカードもギリギリ。前日にQRの不備に気づき貼り直す
- 事前提出について確認しておらず当日頒布停止
準備の反省
ほとんどを前日に用意しました。100均素晴らしいです。
用意したもの
- テーブルクロス(布)
- 見本誌を立てかけるためのやつ (当日忘れる)
- 値段+ポップを印刷したもの
- スケッチブック
- 小物入れ(ペン+DLカード他入れるためのもの)
- 小銭入れ
- 小銭(500円✕5枚、100円✕50枚)
- カッターとか諸々
必要だったもの
- A4くらいのポスターを立てるやつ
- 机の前にはる本の説明書き
- 太いペン
- サークルの名刺
後述するのですがお隣のサークルさんに大変親切にしていただいたのでなんとかなりましたが、 結構色々足りなかったです。特に本が完売してからは何売ってるか全然わからない状態になってしまったので 大きめのポップは必須でした。
サークルの名刺は欲しがる方が結構いらっしゃって、DLカードとよく間違われていました(これは本当に申し訳なかったです)。次回は必ず用意しようと思いました。
当日の反省
取り敢えず一人で参加するのは本を買いに行けないし、トイレも飲み物もままならないし何より寂しいです。なんとかなるかなと思ったましたが当然なんとかなりませんでした。
お隣のサークルの「水晶雫世界」さんには大変親切にしていただきました。お店番を代わっていただいたり、ペンを貸していただいたり、話し相手になっていただいたりと最初から最後まで本当にお世話になりました。こういった方達に出会えただけでも参加して良かったと思います。
まとめ
色々と段取り悪くバタバタしていましたが、本当に楽しかったです。多分次回もまた何か書きます。 ちょっと長くなりそうだったので、戦利品やイベント自体の感想は別の記事にてまとめようと思います。
技術書典スタッフの皆さん、サークル参加の皆さん、当日足を運んでくださった皆さん、お疲れ様でした。 ありがとうございました。
言語ファイルの命名規則と管理方法
今日は言語ファイルの管理方法及び命名規則に関してです。技術書典5でデザインシステムの本を書く予定なんですが、その中でも言語は重要な要素なので一度整理しておこうと思います。
なぜ言語ファイルを管理するのか
実際のところ本当に多言語対応するつもりなのであれば言語ファイルの管理だけでは厳しいところが多いです。言語以外の差異も数多くある上に、UI上で日本語と同じように再現することも簡単ではないからです。それでも言語ファイルを管理したい理由は2点あって
- 用語の更新を簡単にしたいから
- 表記揺れを無くしたいから
です。つまるところUIを再利用可能なコンポーネントの組み合わせで作りたいという欲求と変わりません。
どのように管理すべきか
色々なアプローチがあるのですが、現状私が確認してるもので大きい区分で分けると
- コード中にある文字列を抽出して言語ファイルとして出力する
- 別途言語用のファイルを定義してコード中から呼び出す
の2点があります。前者は何も考えずに渡されたデザインに記述された文字列を記述できるが、表記ゆれは起こりやすい。後者は文字列を別途定義する分コストが高いが設計次第ではサービス内で使用している用語を整理するソースになり得る。といったメリット・デメリットがありそうです。
ちなみに再利用性を考えない設計にした場合には、前者のようなアプローチが良いかなと思います。 どちらの方針を取るかは言語管理の目的を用語の整理とするか、多言語化のための単なる定数とするかで異なります。
どのように設計するか
キーに関してルールがない場合、再現なくネストしていくため、現状私の開発時は <コンテキスト>.<書式>.<適当なキー>
としています。
コンテキスト
コンテキストはスコープを表します。今開発しているプロダクトでは 共通部分のcommon
, ドメイン知識を持つdomain
, 表示領域を表すmodule
で分けています。
common
: ドメインに依存しないような用語、例えば「メールアドレス」などもそれに当たります。domain
: ドメインに依存するような用語、例えば「ユーザー」、「ユーザーの氏名」などです。module
: 表示領域、Viewに依存します。例えば「ユーザー一覧」などがこれにあたります。
コンテキストを用意している理由は適用の範囲を表すことはもちろん、文脈を意識するようにするためです。同じ単語でも文脈が異なれば別の意味を持っている可能性があります。
書式(タイプ)
以下のようなタイプを定義しています。
- label
- button
- message
- placeholder
書式をなぜ用意しているかというと、言語の検索をする際に必要な情報になるからです。また書式のバリデーションの用途も兼ねています。
例えば button
の場合、あとで見返したときに一律して「〜する」という書式になっているのかなどを確認するためです。
コンテキスト間の依存関係
言語間の依存関係は図のようになるはずで、例えばユーザーデータが次のように表される場合
interface User { id: string; name: string; email: string; }
このメールアドレスのキー管理は
const user = { "domain.user.label.email": "ユーザーのメールアドレス" };
としたいのですが、「メールアドレス」の表記がコンテキストによって「Eメール」、「メール」と表記が異なるのはサービスとしてまずいので
const common = { "common.label.email": "メールアドレス" }; const user = { "domain.user.label.email": "ユーザーの{common.label.email}" };
の関係であるべきです(参照の形式は適当です)。同様にユーザー一覧用の言語ファイルは
const userList = { "module.userList.label.user_email": "{domain.user.label.email}", "module.userList.button.ok": "{common.label.ok}", "module.userList.message.hint": "ユーザー一覧でユーザーを追加できます" };
となり、common
、module
から参照可能なものは参照し、固有のものは個別に定義します。
これはモジュールなのかドメインなのか
最早言語ファイルに限った話ではないのですが抽象的なレイヤーが挟まるとどれに入れるべきか迷うことがあるはずです。 例えば「ユーザーを追加する」リンクやボタンの文言はモジュール、ドメインどちらに入れるのか、などです。
正直なところドメインオブジェクトがきちんと分析されているか左右されるのですが、ドメインオブジェクトの振る舞いとしてドメイン配下に定義するのがいいと思っています。 しかしそれをチーム全体に浸透させるのは難易度が高いのも事実なので迷うくらいなら機能の用語としてしまってモジュールに定義するのが良いかと思います。
まとめ
現状実践している言語ファイル管理の方法について簡単にまとめました。言語ファイルを管理する目的によって管理方法は様々なので、まずは目的を整理する必要がありそうです。
AtomicDesignが解決してくれないこと
今日はAtomicDesignについてです。
概要
弊社のとあるチームでAtomicDesignの導入を試みていたのですがあまり上手くいっていないようでした。そこでなぜ上手く行っていなかったのか考えて整理したので、その内容をまとめました。
AtomicDesignとは
Design Language System (DLS) を作る上でのパターンの一つです。詳しくは下記を参照してください。
大まかに説明するとデザインパーツの粒度を定義し、それらの組み合わせでデザインパーツを構成していこうというものです。 粒度は下記のように定義されています。
Organisms > Molecules > Atoms
フロントエンド界隈には大分普及してきたようで最近では活用事例を耳にする機会も多くなりました。
AtomicDesignのメリット
まずはAtomicDesignのメリットについてですが以下の2点がよく挙げられています。
共通言語が作られる
粒度を共通言語として定義することにより、開発者間でのコミュニケーションが円滑に進みます。
分解粒度が属人化しづらい
再利用性の高いUIコンポーネントを作っていく際、どうしても開発者のセンスによるところが大きかったように思えますが、とにかく細かく分解して足し合わせるというメソッドなので属人化しにくいのもメリットの一つと言えるでしょう。
※ しづらい、としたのは限られた階層しか無い以上必ず属人化はするからです。
AtomicDesignで起こりがちな問題
AtomicDesignを採用する時によく起きている問題をまとめました。
分解されている == 良いUIコンポーネントではない
Atomic Designの粒度に分解して配置することを目的にしてしまい、1度しか使わないUIコンポーネントが量産されるケースを現場でよく見かけます。目的は再利用することなので、分解していく過程でどこが再利用出来るかを考えるべきです。
グループ化やパターン化は解決してくれない
良いUIコンポーネントを作るためには適切なグループ化とパターン化が必要です。例えばボタンの場合は下記のようなグループ化、パターン化を行うことで再利用性が高まりますが、AtomicDesignをただ実践するだけではそうはなりません。
Group | Pattern |
---|---|
TextButton | type, size |
IconButton | type, size, icon |
ユーザビリティが良くなるわけではない
UIコンポーネントの分解粒度が最適化されることがユーザーにとって嬉しいわけではありません。あるUIコンポーネントのルールがアプリケーション内で一貫していることで初めてユーザーにとって嬉しいものになります。
そもそも良いUIコンポーネントとは
AtomicDesignをきっかけにDLSを作り始める事自体は良いことです。ただAtomicDesignを実践する前に良いUIコンポーネントとはどういうものなのかを整理し、チェックすると良いかと思います。
再利用性が高いこと
主に開発効率化のためになりますが、UIコンポーネントに関して言えば最も重要な要素です。新たにページや機能を制作する際に、今まで分解したパーツを使用できないか、またそれらをどのようにグループ化されていれば矛盾なくパーツにはめ込めるのかを考えましょう。
最終的には下記のように文字で指示書が書けるのが理想です。
ルールと拡張性のバランス
そのUIパーツが本質的にどういう性質なのかを考えましょう。画面だけ見ていると見えていない性質が見えてくるはずです。 例えば下記のようなナビゲーションバーが提供されている場合
- 左部はページの遷移をコントロールするものである - 中央はページを説明するものである - 右部はページに対するアクションを提供するものである
というルールが考えられます。
ある程度ルールが定まっているとその拡張性の方向も限られてくるため実装も最適化されます。 ルールが定まっていない場合そのUIパーツ内で拡張性の方向が定まらないため、パターン化がしづらくなります。これが1度しか使われないコンポーネントが量産されること、もしくはUIコンポーネントの分岐が多くなる原因になります。
また、必ずしも汎用的なルールに落とし込めないことに注意してください。時には似ている形でも全く別の欲求によってデザインされている場合があります。 こういった場合は無理にパターンに当てはめるのではなく、特殊なケースとして考えるのが良いかと思います。
ちなみに自分はどうしているか
基本的には汎用的なUIコンポーネントと、より詳細度の高いUIコンポーネントの2つを定義しています。(名前は適当です
またユーザービリティを意識した場合、必ずしも汎用性の高いパーツのみで完結するとは限らないため、各ページ内でしか使用しないものも定義することを許容していますが、依存を分かりやすくするためにページのディレクトリ配下に置くようにしています。
詳しくは別の記事でまとめたいと思いますがOOUI(UX)などが近い考え方になると思います。
まとめ
AtomicDesignの実践時によく見かける課題について説明しました。
「設計とはフレームワークではなく良いコードを書こうとする意思である」という言葉も記憶に新しいですが、DLSやUIコンポーネント設計にも同じことが言えます。
手法に名前をつけることは大変意義があることであるのには間違いは無いのですが、ベストプラクティスを考えることが最も重要です。つまり、あるパターンを実践するのを目的とするのではなく、良いUIコンポーネントを作ることを目的としましょうということです。
Xcode9のビルドを高速化する
Xcode9においてビルド高速化するための手法についてまとめました。
設定ファイルの最適化
ビルドの速度に関係する主な項目が下記になります。それぞれの設定の意味と推奨される設定値を解説していきます。
- Build Active Architecture
- Debug Information Format
- WholeModuleOptimization
- XFrontendOptions
- New Build System
Build Active Architecture
Build Settings
>Build Active Architecture
をDebug
時に限りYES
に設定する
実行する対象のArchitectureのみを出力するオプションです。
DebugビルドはデフォルトでYES
になっているはずですが一応確認しておくと良いかと思います。
Debug Information Format
Build Settings
>Debug Information
をDWARF with dSYM
からDWARF
にする
DebugビルドはデフォルトでDWARF
になっていますが、実機ビルドなどでdSYM
が必要になるのであれば下記のように設定することができます。
Whole Module Optimization
このオプションを有効にすることでフルビルドにかかる時間が少なくとも1/2以下になるようです。(とあるプロジェクトで実施したところ 274s
-> 98s
という結果でした。) 下記2つの設定を変更することでwhole module optimization
を有効にしつつ、コードの最適化は実行しないようにします。
Optimization Level
をFast, Whole Module Optimization
に設定するOther Swift Flags
に-Onone
を設定する
whole module optimization
の仕組みについては
Swift.org - Whole-Module Optimization in Swift 3
で説明されています。並列処理は減少することになりますが、重複する処理は減少することにより結果的にビルド速度が向上しているのではないかと思われます。随所で推奨する記事を見かけますが差分コンパイルが劇的に遅くなるので何も考えず入れて良い設定ではないことに注意しましょう。
XFrontend Options
コンパイラの解析部分に対するオプションになります。こちらにいくつかオプションを指定することでコンパイルに時間がかかっているメソッドや式を解析することができます。
-XFrontend -warn-long-function-bodies=limit
Xcode9以前からもあったオプションですが特定のメソッドの解析にlimit
以上の時間がかかっている場合、該当の箇所に警告を出力します。
-XFrontend -warn-long-expression-type-checking=limit
こちらはXcode9から提供されているオプションです。式の解析にlimit
以上の時間がかかっている場合、該当の箇所に警告を出してくれます。前述のオプションではメソッド単位のワーニングしか判別できませんでしたが、このオプションによってより細かく判別することが可能になります。
New Build System
Xcode9から新たに提供されているビルドシステムで、公式では下記のように説明されています。
- New in Xcode 9 – Preview of a new build system written in Swift. Currently, This system is optional but it will become the default in a future version of Xcode - Added a preview of a new build system written in Swift. - Provides higher reliability. - Catches many project configuration problems. - Improves overall build-system performance. Note, build system performance does not include the compilers, linkers, and other tools used by the build system.
- 将来的にはデフォルトで提供されるビルドシステムだがpreviewとしてオプションで使用できる
- 現在より高い信頼性を提供する
- プロジェクトの設定による問題をキャッチする
- 全体的なパフォーマンスを向上させる
- コンパイラやリンカなどのパフォーマンスを向上させるわけではない
とのことで基本的にはメリットしかなさそうです。
下記記事によると28%速度が向上したとのこと。 https://www.linkedin.com/pulse/get-faster-more-stable-xcode-your-swift-projects-dan-zinngrabe/
Framework分割
Frameworkを適切な粒度に分割して差分ビルドしやすい構成にします。Webフロントエンドでもリソース取得の効率化のためにバンドルするファイルを分割することがありますが構成は似たような形になるかと思います。現状XcodeはDynamic Frameworkしかサポートしていないため、起動時間が遅くなってしまうことが懸念されますがStatic Framework化する方法が下記ページにて紹介されています。
Carthage/StaticFrameworks.md at master · Carthage/Carthage · GitHub
また副次的な効果ではありますが依存や設計が整理されるのも大きなメリットかと思います。
まとめ
Xcode開発者の悩みの種であるビルド速度についてまとめました。もしあまり考慮していない場合は参考にして頂ければと思います。ちなみに自分の場合はフルビルドが走った際は、Webフロントエンドの作業に移行するようにしています。