原文:alexkondov.com/full-stack-...
原标题:Picking a Tech Stack
作者:Alexander
系列文章:
了解产品的领域是工程任务的第一步,因为它有助于我们识别具体技术问题。规模、可用性和功能需求都源自业务需求。
我们的任务是选择适合的工具来解决这些问题。
有人常说应该为每项工作选择合适的工具,但如何判断哪种工具是合适的呢?大多数建议到此为止,似乎期望你有一种直觉,当你打开正确框架的文档时,这种直觉会充满兴奋。
遗憾的是,没有丰富项目经验的人很难有这种直觉。你需要一个系统来帮助你缩小选择范围,使你能够独立思考这项任务。
所以我们不会考虑预定义的技术栈,我也不会推崇某种特定技术。因为选择技术栈是一项确定所需工程复杂性的练习,要找到技术能帮助我们达到这一水平。
让我们进一步探讨这意味着什么
工程的过度和不足
即使你自己没有这样做,你也会听到其他工程师抱怨过度设计的代码库。有些产品的构建方式比所需的更为复杂。
即使它们的创造者有良好的意图,他们也让事情变得更糟而不是更好。
复杂性使事情变得更难理解。它们迫使我们在头脑中保留更多的背景信息,并通过更多的代码实现更少的目标。我们必须处理令人困惑的开发过程,其中使用多层抽象、类型和样板代码会使开发陷入停滞。
所有这些反过来又会导致更高的错误机会。
例如,一个简单的展示网站,包含一些表单、图像,也许还有一个简单的预订系统,却用微前端架构构建,每个页面都是独立的应用程序,几个微服务处理表单提交。
这在技术上听起来很神奇,但完全不必要。额外的复杂性会使开发变得更困难,部署更混乱,且可能引发不必要的网络问题。
虽然我们习惯于听到人们抱怨设计过度的产品,但设计不足的产品也同样存在问题。相比之下,它们对于我们试图解决的问题来说太简单了。
我们可能无法预见我们所选择的技术无法应对的基本挑战。一个简单的例子是决定使用普通 JavaScript 构建我们的 UI,因为我们没有考虑到必须构建的所有复杂组件。
它们可能存在可扩展性或性能问题。由于工程师回避创建抽象,因此设计不足的代码库可能会变得过于混乱。在我们试图让事情变得简单的过程中,我们最终可能会得到同样的结果------更慢、更困难的开发。
想象一下,我们决定将数据直接写入文件中,或者只是嵌入一个电子表格,客户可以将数据填写到其中,而不是使用SQL数据库编写我们上面提到的简单的预订系统。
我们将不得不花在修复和管理错误数据上的时间将比我们通过此实现节省的时间花费的时间要多得多。
虽然过度设计是过度思考和规划太远的结果,但工程不足是匆忙开发、预算有限或缺乏对该领域的理解的标志。
但这两个极端都是不好的,因为我们未能充分满足产品的要求。
选择更少的害处
需要强调的是,我认为工程设计不足是两害相较取其轻。系统总能在需要时变得更加复杂,相反则不然。
我见过更多项目因过度工程而苦苦挣扎。不切实际地应对未来潜在问题,导致代码库过于复杂且难以维护。过度设计的代码库开发速度缓慢,并不能使软件质量更高。
过度设计的代码库在开发速度方面要差得多。较慢的开发速度并不能使软件变得更好。
事实上,我们应致力于创造一个易于理解和快速迭代的环境。只要迭代周期更快,我们就能更频繁地改进代码和架构,从而快速响应变化。
这个周期越长,我们迭代的频率就越低。
因此,当有疑问时,请始终倾向于设计不足而不是过度设计。
设计得恰到好处
我们不想陷入这两个极端中的任何一个,因为它们都具有潜在的危害。我们希望处在"设计得恰到好处"的中间位置,这样既能高效地工作,又能使用足够强大的工具和抽象。真正的美德总是在平衡中体现。
当用简单的锤子就能在墙上安放螺栓时,我们没有必要使用钻孔机。然而,编程比这复杂得多,选择"最佳工具"涉及更多因素。因此,我准备了一些问题来帮助我们缩小技术选择的范围。
这将在 Prod 中存活多久?
首先要问自己的一大核心问题是,该产品将在生产环境中存活多长时间。这听起来似乎很奇怪,但请相信我,继续往下看。
一个运行多年的应用程序会不断地变化。它将被重构和扩展,库会更新,甚至其运行环境也可能改变。业务部门会调整战略,这些调整会以各种方式反映在代码库中。
因此,你需要一种能够提供良好结构和可读性的技术。这种技术应拥有广泛的社区支持,因为许多工程师会接手这个项目,他们需要能够读懂它。
换言之,你需要更加保守的选择。
而对于那些可能在一个月甚至一年内就会被抛弃的原型来说,你可以更加随意。如果你在一家寻找产品市场契合度的初创公司工作,纠结于完美的代码结构没有意义。
当你构建的东西的寿命较短时,无需过多顾虑未来。你可以编写无法扩展的代码,尝试新技术并进行实验。如果不用偿还技术债务,可以更加大胆地承担技术债务。
某些技术在企业中比在初创公司中更为常见,反之亦然。这是因为它们的需求和应用程序生命周期不同。
如果不认识到这一点,就会导致初创公司过度设计应用程序,或者企业内部项目在团队间转移时变得混乱。
现在,相信你在阅读这篇文章时,脑海中已经浮现出一些适用于不同情况的技术。
有时它们可能会有重叠。例如,在撰写本文时,我会在企业和初创公司环境中都使用 React,因为它既提供了一个稳定的社区,也给予了我在快节奏环境中所需的灵活性。
一切都取决于你期望软件的寿命。
你能使用你熟悉的工具吗?
在这一点上,我确信FOMO(错失恐惧症)是行业快速发展的主要驱动力之一。
除非使用最新版本的前端框架、低级语言和可扩展的数据库,否则你可能认为无法构建出完美的应用程序。
我们不断更换技术,并没有太多客观好处,只因为担心错失关键功能。事实上,许多复杂的软件都是使用远不如我们现有工具强大的工具编写的。
请记住,你对某项技术的经验胜过它的潜在优势。了解避免哪些陷阱和使用哪些模式会帮助你构建良好的结构,同时提高生产效率。
工程师使用熟悉的工具可以产出更好的产品,因为他们已经了解生态系统和支持工具。他们可以与社区成员交流,并了解常见的反模式。
无论你经验多么丰富,熟悉新工具都需要时间。
另一个相关问题是------你的团队使用哪些工具?如果团队中有3名经验丰富的Angular开发人员,选择React就没有意义。任何你能用一个前端框架构建的程序,也能用另一个框架构建。同样,大多数语言都可以用来编写足够好的REST API。
因此,除非有特定技术问题,否则应该优先考虑过往经验来选择技术栈。
你的团队是如何组织的?
康威定律指出,每个组织都会构建一个反映其沟通结构的系统。我们很容易低估外部因素对技术决策的影响,这是一个很好的例子。
沟通越顺畅,产品的各部分就越少出现问题。沟通和决策越困难,我们就需要更多的自主权,以维持生产效率。
因此,我们将产品拆分为由特定团队管理的小部分。
在小团队中,一个人可能负责单体应用程序中的一个模块。在大团队中,可能是一整个服务。在大公司中,一个团队可能会负责整个系统中的若干服务。
随着团队的发展,这种划分会自然而然地发生。然而,为了优化架构,可以主动围绕团队结构来设计产品。
这种逆康威单声道的实践相对流行。
在实际操作中,这意味着如果有三个在同一办公地点的全栈工程师处理同一个产品,那么模块化的单体应用将是一个不错的选择。如果团队分为前端和后端团队,单独的存储库并通过REST API通信会更合适。
沟通越顺畅,开发过程就越高效。
平衡是一个移动的目标
这不是一份静态的问卷,你只需填写一次即可用作北极星。适当的工程复杂度水平是一个不断变化的目标,它将随着公司的发展而变化。
突然之间,你的原型成功了,现在企业希望你继续在此基础上进行构建。
但这改变了代码库在生产环境中生存多长时间的基本思想。你在这里和那里偷工减料,知道你的工作将被重写。现在,当产品经过验证时,它的寿命比预期的要长。
你最初的决策不足以支持产品,你需要重构。
也许该公司在不同的时区雇用了一个团队,现在拉取请求拖延了好几天。一个团队的工程师在离开之前破坏了构建,现在另一个团队必须弄清楚出了什么问题。安排会议变得更加困难,但也更加必要。
慢慢地,一个好的初始设计可能会在一瞬间变得过时。
组织问题可以通过模块化项目甚至将其拆分为单独的技术解决方案来解决。
这绝不能被视为对上述事件的批评。一家初创公司正在寻找快速进入市场的方法,而一家公司扩展到新地点是完全正常的。作为工程师,我们如何在代码中反映这些更改非常重要。
技术栈无关紧要
你选择的确切技术并不重要......只要它们符合上述问题的答案。如果这些技术符合你对速度、稳定性、社区和先前经验的需求,那么你的选择取决于个人品味。
库的 API 不会成就或破坏你的产品,因此不要沉迷于它们。
但毕竟,我至少需要在技术方面提供一些技术指导。在撰写本文时,你需要一个很好的理由不选择 React 作为前端,而选择 Postgres 作为数据库。
它们似乎满足了所有条件,并且在小公司和大型企业中都使用。如果其他一切都失败了,请从那里开始。