原則
このページでは、Tuistの設計と開発の柱となる原則について説明します。 これらの原則はプロジェクトとともに進化し、プロジェクトの基盤に適切に合致する形で持続可能な成長を保証するために存在します。
慣習を基準にする
Tuist が存在する理由のひとつは、Xcode が慣習に乏しく、それによって複雑で拡張性や保守性に難があるプロジェクトにつながっているためです。 そこで Tuist は、単純かつ綿密に設計された慣習に、まずは従うというアプローチを取ります。 開発者は慣習から外れることもできますが、それはわざわざ行うことであり、自然に感じられない意識的な決定です。
たとえば、ターゲット間の依存関係を定義するとき、提供されたパブリック・インターフェイスを使用するという慣習があります。 これにより、Tuist はリンクが正しく動作するようプロジェクトを生成できます。 開発者はビルド設定を通じて依存関係を定義することも可能ですが、それを行うと暗黙的な定義になり、tuist graph
や tuist cache
のように特定の慣習に依存する Tuist の機能が正しく動作しなくなる恐れがあります。
慣習を既定とする理由は、開発者が行う決定をできる限り Tuist 側で肩代わりすることで、アプリの機能開発に専念できるようにするためです。 慣習がない状態では、大小さまざまな決定を下す必要があり、それらが一貫性を欠いた場合に複雑さが増していき、管理困難になってしまいます。
マニフェストを信頼できる唯一の情報源とする
多層な設定やそれらの間をつなぐコンテキストを持つと、プロジェクトの設定を理解し保守することが困難になります。 一般的なプロジェクトで少し考えてみてください。 .xcodeproj
ディレクトリにプロジェクト定義があり、CLI の設定はスクリプト(例: Fastfiles
)の中にあり、CI のロジックはパイプラインにあります。 これらは三つの層が存在し、相互の間でコンテキストを維持する必要があります。 プロジェクトを変更してから一週間後にリリーススクリプトが壊れていたと気づいた、というような経験はありませんか?
これを簡単にする方法は、マニフェストファイルだけを信頼できる唯一の情報源とすることです。 これらのファイルは、Xcode プロジェクトを生成するために必要な情報を Tuist に提供します。 また、ローカルおよび CI 環境でプロジェクトをビルドするための統一されたコマンドを可能にします。
Tuist は複雑な部分を引き受け、開発者ができるだけ明示的にプロジェクトを記述できるように、シンプルかつ安全で使いやすいインターフェイスを提供する必要があります。
暗黙を明示化する
Xcode は暗黙的な設定を数多くサポートしています。 依存関係を暗黙的に推測する仕様が好例でしょう。 小規模プロジェクトなど単純な設定であれば暗黙的な振る舞いでも問題にならない場合がありますが、プロジェクトが拡大するとビルドの遅延や予期せぬ挙動を引き起こしかねません。
Tuist は Xcode の暗黙的な挙動に対応する明示的な API を提供するべきです。 Xcode の暗黙的な設定をサポートする必要はありますが、最終的には開発者が明示的なアプローチを選択しやすい仕組みであることが望ましいです。 Xcode の暗黙や複雑さをサポートすることで、Tuist の導入障壁が下がり、チームは徐々に暗黙を排除していくことができます。
依存関係の定義は良い例です。 ビルド設定やビルドフェーズを通じて定義することもできますが、Tuist が提供する美しい API を使うことで、より自然に依存関係を明示できます。
API を明示的に設計することで、Tuist がプロジェクトに対して行うチェックや最適化が可能になります。 さらに、依存関係グラフをエクスポートする tuist graph
や、ターゲットをすべてバイナリとしてキャッシュする tuist cache
のような機能も利用できるようになります。
TIP
Xcode から機能を移植しようという要望がある度に、その概念をシンプルかつ明示的な API に落とし込むチャンスと捉えるべきです。
シンプルに保つ
Xcode プロジェクトが大規模化するときの主な課題のひとつは、Xcode がユーザーに多くの複雑さを直接さらしていることです。その結果として、一部のメンバーしかプロジェクト全体やビルドシステムのエラーを理解できず、暗黙知がチーム内に偏在しがちです。 これはチームが少数の人に依存するリスクを抱えることになり、好ましい状況ではありません。
Xcodeは優れたツールですが、長年の改良や新プラットフォーム、プログラミング言語の追加により、シンプルなインターフェースの維持が難しくなっています。
Tuist は、この機会を活かして物事をシンプルに保つべきです。シンプルなものを扱うのは楽しいし、モチベーションも上がります。 経過時間が長いコンパイルプロセスの最後で発生する不可解なエラーの解析や、「なぜデバイスでアプリが動かないか」を延々と調べるような作業に時間を費やしたくはありません。 Xcode は内部のビルドシステムにタスクを委譲しますが、そのエラーがユーザーにとって分かりやすい形で返ってくるとは限りません。 "framework X not found" というエラーを見ても、どう対応したらいいか分からないということはよくある話ですよね? もし根本原因の候補を一覧で提示してくれたらどれほど助かるでしょう。
開発者体験を起点にする
Xcode に関するイノベーションが乏しい(あるいは他の環境ほど盛んではない)理由のひとつは、既存の解決策を起点に問題を分析することが多いからです。その結果として、現在ある解決策の多くは同じようなアイデアやワークフローの範囲にとどまっています。 既存の解決策も検討に入れるのは良いことですが、それだけに縛られてしまうと創造性が制約されてしまいます。
私たちは Tom Preston が このポッドキャスト で語っている考え方を参考にしています。「プログラミングによるソリューションは、それが物理的に不可能でない限り、頭の中で想像するほとんどのことを実現できる」という趣旨です。つまり、開発者体験がどうあってほしいかをまず想像しさえすれば、実現までは時間の問題にすぎません。開発者体験を起点に問題を分析すれば、ユーザーに好まれるような独自の解決策にたどり着けるでしょう。
私たちは、皆と同じ行動を取りたくなる誘惑に駆られることがあります。たとえそれが、皆が絶えず不便だと感じている事柄に固執することを意味していたとしても。 そうしないでください。 アプリをアーカイブする理想の形はどうか? コード署名をもっと快適にするには? どんなプロセスなら Tuist で効率化できるか? たとえば Fastlane 対応を検討する場合でも、まずは問題がどこにあるのか、なぜ必要とされているのかを掘り下げることが大切です。 「なぜ」という質問をすることで、問題の根本にたどり着くことができます。 モチベーションがどこから来るのかを絞り込めば、Tuistがどのように彼らを最善の方法で助けることができるかを考えることができる。 最終的な解決策として Fastlane との連携が正しい場合もあるかもしれませんが、それ以外の選択肢があるかもしれません。十分に検討し、トレードオフを理解したうえで最良の手段を選ぶことが重要です。
エラーは起こるもの
私たち開発者には、エラーは起こり得るという事実を軽視しがちな部分があります。 そのため、理想的なシナリオのみを想定してソフトウェアを設計・テストしてしまうことがよくあります。
Swift の型システムや適切なアーキテクチャ設計は多くのエラーを防ぐのに役立ちますが、それでもコントロール外の要因から発生するエラーは防げません。 ユーザーが常にインターネット接続できるとは限りませんし、システムコマンドが常に成功するとも限りません。 Tuist が動作する環境は私たちの制御下にあるサンドボックスではないので、どのように変動して Tuist に影響を与えるかを理解する努力が必要です。
エラーを適切に処理できないと、ユーザー体験は損なわれ、プロジェクトへの信頼も失われる可能性があります。 Tuist のあらゆる側面をユーザーが楽しめるようにしたいと考えています。
私たちはユーザーの立場に立って、エラーが伝えるべき内容を明確に想像するべきです。 プログラミング言語がエラー伝播のコミュニケーション手段であり、ユーザーがそのエラーの受け手であるなら、エラーはユーザーが理解する言語で記述されるべきです。 何が起こったのかを知るのに十分な情報を含める必要がありますし、関連性のない情報を隠す必要があります。 また、問題を解決するためにどのようなステップを実行できるかをユーザーに伝えることで、実用的であるべきです。
そして最後に、私達のテストケースは失敗するシナリオを熟考するべきです。 これによって、意図通りにエラーを処理できているかを保証し、将来的に他の開発者がそのロジックを壊すのを防ぐことができます。