无论哪种公司都需要管理资金、技术,以及风险。其中,初创公司所要面临的巨大风险使其不得不转变传统理念,将风险转化为前进的动力,以更快地获取经验。初创公司的起始可以选择绿野仙踪测试法,或者是从一个不被大公司看好的 MVP 落地页开始。
我在创业之初时,对自己无法更快地做出技术栈相关决策非常不满。如今,我已经在 TeamViewer 工作了好几年,在给五百强公司做过几个项目后,学到了不少技巧,并愿意在此分享出来。
这篇文章将引用《独角兽项目》这本书中的虚构角色 Erik,以采访的形式进行分享。Erik 是创建了“DevOps 的三种方法的”的传奇人物,希望在这次采访中他能够帮到我们。
Stefan Miteski:Erik,让我们开门见山直切入主题吧。团队在构建 MVP 时,什么时候可以从“尽可能快”的理念转换为构建可延展性更强、更适于维护、可持续性更高的模式呢?
Erik:首先,不是所有的构想都需要代码来实现,用最便宜、最快的就行。我更倾向于选择能够最快完成任务的技术,哪怕这意味着我要用的某个低代码平台需要我在后续重写全部的代码,也都不是问题。所以这其实是一个基于团队技术背景的决定。如果团队中有人懂 NodeJS,那就选择 NodeJS,如果有人会 Python 那就用 Python。在这个阶段你不需要考虑最佳的质量过程、CI/CD,或者最佳敏捷方法。这些多余的累赘是初创公司在起始阶段不应思考的问题。在 MVP 阶段,你只需要做在黑客马拉松里会做的事。
简单来说,只有在拥有可能的收入资金后,可扩展性和流程才会变得重要。
Miteski:假设钱不是问题,那么在大公司中开发新项目这种情况呢?
Erik:这种情况也类似。在确保生存能力后再考虑可延展性。如果项目还在试水阶段,那就按照 MVP 的规划运行。如果项目已经稳定了,那这时候再考虑可延展性。
Miteski:确实,这么说就很明确。我常在指导初期创业者时,遇到很多的失败案例都是因为过早地在可延展性上消耗了太多的精力。由于构建的产品没人需要而导致的失败率(35%)要远高于错误的技术决策所导致的创业失败(8%)。
那么在扩容阶段呢?我们现在已经有了稳定的收入,终于可以抛弃初期乱糟糟的代码垃圾场了,这时我们应该选择什么技术呢?
Erik:根据康威定律,“设计系统的组织被限制生产设计,这些设计是这些组织的通信结构的副本。”所以在这个阶段,我们应考虑的是组织整体的结构设计,而不仅仅是技术栈或软件架构。组织需要的团队数量、团队间的合作模式是什么?如何保持团队间的统一性?测试的流程是什么?CI/CD、发现策略怎么制定?如何实现营销和开发工作的一致性?如何确保企业文化的健康发展?如何获取并整合人才?
所有的技术都是建立在问题解决的基础上,当然项目也是如此。然而,网页应用的后端该用 Java 还是 C# 开发?数据库该用 SQL 还是 MySQL?这类问题的答案可能就不是那么的明显了。最直接的答案是在“应急架构原则”和“最后责任时刻”规则的前提下,将决定权交给团队,并从功能性和非功能性两方面深入研究。
其中,非功能性要求有:
线上社区的规模。如果你选择了 C# 而不是什么新奇的编程语言,那么除了完善的文档之外,你还将拥有来自 Jon Skeet 等人的支持,他在 StackOverflow 上已经有超过一百万的声望点数。也就是说,你能在互联网上找到 C# 语言相关问题答案的几率要远高于其他小众语言。除此之外你还要考虑这种语言可用的库有多少,支持是否成熟等问题。
用工市场的规模。附近大学的学生学的都是什么语言?当然,你也可以针对需要的技术对员工进行培训,但这又要搭进去大量项目开发时间。再加上如果你想要使用的语言并不常用或者是过时很久了,那么你还需要更高的预算以支付更高的薪酬。
系统的寿命。人类的寿命大概 70 年左右,而且还需要 9 个月才能从胚胎发育成人。如果我们想让系统持久存活,也需要类似的方法。这应该是长期的技术策略,而不是取决于我们所做的第一个决策。
在上线之后再做出系统重大改动有时感觉像在飞行时修理飞机。因此,将对系统而言至关重要的决策推迟到“最后责任时刻”是很明智的。
Miteski:那么什么是“最后责任时刻”呢?
Erik:这个概念来源于精益开发。返工的代价要远高于延迟的成本。而敏捷开发提倡经验主义——在实践中学习。如果你过早地做出不可逆转的决定,那么要承担的风险也会加倍。因此,我们需要谨慎决策,将其中可以学习的部分挑出来,以在做出重大决策前降低风险。
Miteski:"延迟"听起来像是与精益初创的原则相悖?毕竟速度是我们的主要竞争优势。
Erik:延迟决定不代表原地不动地思考问题。我们要围绕这个决策对架构进行探索,了解业务情况、用户需求,这样才能在最后责任时刻做出最佳选择。我们还可以做个模拟系统,并围绕其构建各种 API。
Miteski:那么,业务情况又是怎么影响技术栈选择的决策呢?
Erik:可以有很多方面:
确定你的竞争优势,以及可以为这种优势提供最好支持的技术。
将与组织竞争优势无关的各种技术解决方案交由第三方处理,掌控并构建属于自己的技术栈,后者才是竞争优势的一部分。这种理念适用于所有技术及非必要服务。但要注意,不要让你的供应商发展成自己的竞争对手。当年微软和英特尔可都曾是 IBM 的供应商。
如果不是必须采用裸机的话,那么云供应商是个不错的选择。但该选哪个供应商呢?还是那句话,这要取决于业务的本质。如果你的客户非常在意云服务在事故期间的反应速度,那么就仔细研究它们的 SLA 以及可以建立的合作伙伴关系类型。如果不是,那就以它们能提供的服务为标准参考。从基础的 CloudWatch 到内容丰富的 Kubernetes之类,哪一种可以持续加快你的部署速度?最后,不要忘了价格因素。选择云合作伙伴就像选择你初创公司的合伙人,不要着急,不要急于求成,这样也方便将来深度集成他们的服务。
Miteski:那么,随着组织的成熟发展,我们可能会面临什么陷阱吗?
Erik:首先是电车陷阱。这种陷阱通常会出现在不健康的组织环境中。我听说过的一个例子是,曾经有位工程师负责了某个科技巨头项目中绝大部分的主要功能,并借此要挟公司涨薪。在没有得到想要的结果后他离开了公司。最终公司迫于无人能维护而只能重做整个项目。
导致竖井的原因之一是管理层对快速交付的施压。因为在高压环境下,拥有特定技术背景的开发者会效率更高,所以在处理技术负债时,我们还需要将反竖井纳入考虑范围内。
但无论竖井为什么会出现,我们都需要意识到它们的存在是非常危险的。甚至很多大公司都会犯下把多位专业领域的工程师放在同一个篮子里的错误,万一这个篮子出了什么事,可能会影响到公司的存亡。如果这是你的公司正在做的事,那么是时候考虑换种方法做事了。将技术知识传播开,应用代理策略,让不在这个篮子里的其他工程师也开始做这部分的工作,只在“代理工程师”们被问题卡住时再咨询篮子里的专家。这种方法会短暂降低效率,但它确保了长期的鲁棒性,而且后续我们的工作效率会更高,你看是不是这个道理?
Miteski: 确实。
Erik:另一个要注意的是奶狗陷阱。有时候天真烂漫的想法会让我们沉浸其中无法自拔。就像是看着可爱的小奶狗,我们会因为它们当时可爱的外表和一瞬间的心动而决定收养它们,但却忽略了它们在未来十多年中的成长,并且在这期间需要不断地照料。在很多情况下,技术解决方案也会持续存在超过十年,我们在做技术决策时也需要将这点纳入考量范畴。我们不能为了某个工程师酒后天马行空的想法或产品经理在飞机上看杂志而脑洞大开的灵感,就把未来全部贡献进去。Visual FoxPro 在上世纪九十年代听起来像是个绝赞的新技术,但它并没有经受住时间的考验。类似的例子在科技坟地里并不少见,而随着现在前沿新科技发展的步伐,在未来这片坟地大概是不会寂寞了。
但反过来说,将所有新想法和实验性项目全部拒之门外也是很危险的。用微服务或低耦合系统,把系统中独立的一部分作为新技术的试验场,这种方法很适合实验性创新。如此一来,我们就可以在生产环境中实验新技术,而由于试验场并不与主要功能挂钩,且位置也不是很关键,后续如果需要关闭这部分功能也不会影响到客户使用。仍处于开发阶段的技术很危险,但我们可以用这个试验场来获得技术实操的经验,测试技术栈在现实场景中的表现并完善对它的认知。
Miteski:如果遵照“最后责任时刻”规则,并让组织中的所有团队选择自己想要的技术栈,我们就会遇到一个困境,该如何平衡团队选择的自主性和公司技术栈的统一性呢?
Erik:组织的管理层应当设定一个技术方向,并设立一套宽泛的原则以做决策。公司所有团队都使用类似的技术栈所带来的优势很明显:在购买软件使用权时能够有更好的议价;在新需求出现时,团队能够迅速重组,提高组织的适应性;技术挑战一经解决,技术知识点传递给公司上下全体成员。
这么做也有缺点。随着市场需求和公司所提供的解决方案复杂化,对团队技术栈的多样性要求也就越高。也就是说,基础原则是确立一个技术栈方向,但同时也要给予团队做出偏离指示的自治能力。不过团队也要阐述清楚不遵循公司技术大方向的原因所在。
Miteski:微服务之类的低耦合方法可以让不同团队使用不同的编程语言搭建服务或系统部件,这种层级的灵活性的确可以带来一定的优势,那么我们应该在何时利用这种优势呢?这种情况下是否也有基础准则?通常情况下工程师都会知道该怎么做,但在创建新的技术栈时他们的目的可能并不单纯。我见过有的工程师想用Go来编写服务,仅仅因为他们觉得 Go 这个新语言看起来很酷,想要学习 Go。
Erik:低耦合基本不会出错,而多种编程语言也会促进公司发展。最关键的是变化,从一个微小的变化开始,如果效果好,那我们就从中学习,鼓励其他团队在其基础上发展。根据公司及代码的规模不同,公司整体的技术栈向一个新方向转变所需时间也各不相同。持续的演变与渐进的转化总比一刀斩从头开始的痛苦要小。这种情况下我们的基本原则是,限制并规划这些新语言或新技术的探索,在系统或服务的非关键部分进行测试。随时切断这些实验服务而不影响主要功能。让发展与技术变革从服务末梢开始,从最微不足道的影响逐步向服务中心靠拢,让全部系统和代码基础缓慢发生变化。在已经开始了向内推动且尚未到达系统核心的变更浪潮后,我们很少会再开创全新的发展潮流。
聚焦于让我们能够以可持续的方式高速发展的东西,同时也不要忽视运维的作用,这样才能更快、更安全,也更快乐地交付更高价值的产品。
Miteski: 多谢!我很享受这次的对话。我相信任何的公司都应该不时来读一读这篇文章。
Erik: 谢谢,记得在你重温《独角兽项目》时再来看看我。
---
原文链接:
Rules of Thumb & Traps When Approaching Tech Stack Decisions
评论