# 原则 {#principles} 本页介绍了作为 Tuist 设计和发展支柱的原则。这些原则随着项目的发展而变化,旨在确保与项目基础保持一致的可持续发展。 ## 默认为约定 {#default-to-conventions} Tuist 存在的原因之一是因为 Xcode 在约定俗成方面比较薄弱,这就导致了复杂的项目难以扩展和维护。为此,Tuist 采用了一种不同的方法,默认使用简单而设计周密的约定。**开发人员可以选择不遵守约定,但这是一个有意识的决定,感觉并不自然。** 例如,通过使用提供的公共接口定义目标之间的依赖关系就是一种惯例。通过这样做,Tuist 可以确保生成的项目具有正确的配置,从而实现链接。开发人员可以选择通过构建设置来定义依赖关系,但这样做是隐式的,因此会破坏 Tuist 功能,如`tuist graph` 或`tuist cache` ,这些功能都依赖于对某些约定的遵循。 我们之所以默认使用约定俗成的方法,是因为我们能代表开发人员做出的决定越多,他们就越能集中精力为自己的应用程序设计功能。如果我们没有约定俗成的规则,就像许多项目中的情况一样,我们不得不做出与其他决定不一致的决定,结果就会出现难以管理的意外复杂性。 ## 表象是真理之源 {#manifests-are-the-source-of-truth} 多层配置和它们之间的合同会导致项目设置难以推理和维护。试想一下一个普通的项目。项目的定义存在于`.xcodeproj` 目录中,CLI 存在于脚本中(例如`Fastfiles` ),CI 逻辑存在于管道中。这是我们需要维护的三个层次,它们之间存在契约。*您是否经常遇到过这样的情况:您更改了项目中的某些内容,一周后却发现发布脚本崩溃了?* 我们可以通过清单文件这一唯一的真相来源来简化这一过程。这些文件为 Tuist 提供了生成 Xcode 项目所需的信息,开发人员可以使用这些项目来编辑他们的文件。此外,它还允许使用标准命令从本地或 CI 环境构建项目。 **Tuist 应该自己承担复杂性,并提供一个简单、安全和令人愉快的界面,尽可能明确地描述他们的项目。** ## 将隐性变为显性 {#make-the-implicit-explicit} Xcode 支持隐式配置。一个很好的例子就是推断隐式定义的依赖关系。虽然隐式配置对于配置简单的小型项目来说并无大碍,但随着项目规模的扩大,它可能会导致速度变慢或出现奇怪的行为。 Tuist 应为隐式 Xcode 行为提供显式 API。它还应支持定义 Xcode 的隐含性,但实现方式应鼓励开发人员选择显式方法。支持 Xcode 的隐含性和复杂性有助于 Tuist 的采用,之后团队可以花一些时间来摆脱隐含性。 依赖关系的定义就是一个很好的例子。虽然开发人员可以通过构建设置和阶段来定义依赖关系,但 Tuist 提供了一个漂亮的 API,鼓励开发人员采用该 API。 **显式 API 的设计使 Tuist 能够对项目进行一些检查和优化,而这些检查和优化在其他情况下是不可能实现的。** 此外,它还启用了一些功能,如`tuist graph` ,可导出依赖关系图的表示,或`tuist cache` ,可将所有目标缓存为二进制文件。 ::: tip 我们应将每一个从 Xcode 移植功能的请求都视为一个机会,通过简单明了的 API 来简化概念。 ::: ## 保持简单 {#keep-it-simple} 扩展 Xcode 项目时面临的主要挑战之一来自于这样一个事实:**Xcode 向用户暴露了大量的复杂性。** 因此,团队的总线系数很高,团队中只有少数人了解项目和构建系统抛出的错误。这种情况很糟糕,因为团队依赖于少数几个人。 Xcode 是一款伟大的工具,但这么多年来的改进、新平台和编程语言都反映在其表面上,很难保持简单。 Tuist 应该抓住机会,让事情变得简单,因为做简单的事情既有趣又能激励我们。没有人愿意花时间去调试一个发生在编译过程最后的错误,也没有人愿意去理解为什么他们无法在自己的设备上运行应用程序。Xcode 将这些任务委托给其底层构建系统,在某些情况下,它很难将错误转化为可执行的项目。您是否遇到过*"framework X not found"* 错误,却不知道该怎么办?试想一下,如果我们能得到一份错误的潜在根源列表,那该多好。 ## 从开发人员的经验出发 {#start-from-the-developers-experience} Xcode 缺乏创新的部分原因,或者换句话说,不如其他编程环境中的创新多,是因为**我们经常从现有的解决方案开始分析问题。** 因此,我们现在发现的大多数解决方案都围绕着相同的想法和工作流程。将现有解决方案纳入方程固然是件好事,但我们不应让它们束缚我们的创造力。 我们喜欢用汤姆-普雷斯顿(Tom Preston)(https://tom.preston-werner.com/)在[本播客](https://tom.preston-werner.com/)中所说的话来思考:*"大多数事情都是可以实现的,只要在宇宙的限制范围内,你头脑中的任何想法都有可能通过代码实现"。* 如果**,我们想象我们希望开发人员的体验是怎样的** ,那么实现它只是时间问题--从开发人员的体验出发来分析问题,会给我们带来独特的视角,让我们找到用户喜欢使用的解决方案。 我们可能会受到诱惑,想效仿大家的做法,哪怕这意味着要忍受大家不断抱怨的种种不便。我们不要这样做。我如何想象归档我的应用程序?我希望如何进行代码签名?Tuist 可以帮助我简化哪些流程?例如,添加对[Fastlane](https://fastlane.tools/)的支持就是一个解决问题的方案,我们需要先了解这个方案。我们可以通过问 "为什么 "来找到问题的根源。一旦我们缩小了动机的范围,我们就可以思考Tuist如何才能最好地帮助他们。也许解决方案是与Fastlane整合,但重要的是,在做出取舍之前,我们不能忽视其他同样有效的解决方案。 ## 错误可能会发生 {#errors-can-and-will-happen} 我们开发人员有一种固有的诱惑力,就是无视可能发生的错误。因此,我们在设计和测试软件时只考虑理想情况。 Swift、其类型系统和架构良好的代码可能有助于防止某些错误,但不是所有错误,因为有些错误是我们无法控制的。我们不能假定用户总是有网络连接,也不能假定系统命令会成功返回。Tuist运行的环境并不是我们所能控制的沙盒,因此我们需要努力了解这些环境可能发生的变化以及对Tuist的影响。 错误处理不当会导致糟糕的用户体验,用户可能会失去对项目的信任。我们希望用户喜欢 Tuist 的每一个部分,甚至是向他们展示错误的方式。 我们应该设身处地为用户着想,想象一下我们希望错误告诉我们什么。如果编程语言是错误传播的通信渠道,而用户是错误的目的地,那么就应该用目标(用户)所使用的语言来编写错误报告。错误报告应包含足够的信息以了解发生了什么,并隐藏不相关的信息。此外,错误报告还应具有可操作性,告诉用户可以采取哪些措施来弥补错误。 最后但并非最不重要的一点是,我们的测试用例应该考虑失败的情况。它们不仅能确保我们按规定处理错误,还能防止未来的开发人员破坏逻辑。