Blog
Blog
PHODAL

软件开发是一项复杂的集体活动,它涉及到一系列的行为和艺术,如项目管理、流程管控、知识转化、程序员心理学(狗头)等。从个体出发时,这些都是一些无关紧要的因素。作为一个 “螺丝钉”,我们所关心的是:如何去解决问题?当然了,我们把组织视为一个个体时,我们也只关心:如何去解决问题?

PS:本文所针对的场景,都是复杂业务场景下的 Web 应用。简单的 Web 应用不适合复杂的架构模式,它为带来巨大的成本。 在接触了领域驱动设计的概念,其中关于核心域的想法让人颇为激动。而在微服务架构中,核心域是一个或者多个服务的域,而位于核心域的核心则是领域模型。简单地来说,对于一个系统来说,它的核心的核心的 ”核心“ 就是:领域模型。 过去,当我们谈及领域模型的时候,我们往往将其置于 Web 后端的领域。当我 GET 了一些基本的理念之后,便尝试整合到前端架构中。去年,我开始了 在项目上的第一次尝试,并在 GitHub 上创建了 [clean-frontend](https://github.com/phodal/clean-frontend) 项目,它以 Angular 作为示例,介绍了如何开发一个整洁前端架构的前端应用。 ## 引子 1:模型一致化 我习惯于在公司的项目中引入成熟的框架,从几年前的 Angular.js 到近几年的 Angular,完整的框架能为企业带来更少的维护成本,从而降低软件开发成本。几年前,我们引入了 Angular 之后,便开始大量地 TypeScript 项目实践。作为一个支持静态类型的语言,它非常适合于开发大型应用、企业应用,在这一点上你可以从 React、Vue 等框架建议使用 TypeScript 看到一种趋势。 采纳了 TypeScript 之后,当前端从后端获取到数据之后,那么它需要将 JSON 数据映射到对应的 interface。如此一来,前端的模型也就有了对应的领域模型。而这个数据模型和后端的数据模型应该是完成一致的,但是实际上,它往往是落后的。后端的 API 发生的变更之后,才需要前端同步去修改模型。 而当我作为一个前端的 Tech Lead 来考虑这个问题的时候,我首先想到的是:读取后端的 Java 代码,然后生成对应的前端模型。在没有造 Chapi 的轮子之前,通过 TypeScript Compiler 转换获得对应的类型,是我觉得比较靠谱的方案。在有了 Chapi 之后,我觉得它们都是小问题了。 不过,然后我一想这样做的意义并不大,还不如:套用后端的契约测试,造一个前端的自动化契约测试,即:[mest](http://github.com/phodal/mest)。它通过 API 返回数据和 TypeScript 的 Interface 来完成对于契约的测试。一个简单的测试数据如下: ```csv url,interface https://phodal.github.io/mest-test/error.json,mock/IError.ts ``` 通过 HTTP 请求获取对应的测试数据,再将其与本地的模型进行比较。 不过呢,我们还要使用 JavaScript 语言重写部分 Java 代码,那么我们为什么不要 JavaScript / TypeScript 重写一切呢? ## 引子 2:JavaScript / TypeScript 重写一切 遗憾的是,使用 JavaScript 编写后端应用(BFF、胶水层除外),在大部分的大公司是比较难的。内部的生态链和运维影响了技术决策,使用 C++ 不香吗,使用 JavaScript 会存在无人在背后支持。 ### 纯 Node.js 后端应用 在过去的几年里,我建议:小公司的后端应用**不要**使用 JavaScript / TypeScript 编写,因为运维、监控、APM 等生态尚不够完善。小公司应该优先投资于业务领域,在基础设施的投入见效比较短,除非能控制好开发人员的流动性。 不过,不管怎样,已经有大量的小公司因为人力成本的原因,已经使用上了 Node.js 来开发后端应用。 ### Serverless 应用 而随着 JavaScript 系生态的完善,基础设施已经不是会成为小公司的负担,我便觉得这是一个好的时机。不过,我指的是采用 Serverlesss 架构,而非自建 JavaScript 系生态。Serverless 不仅帮助小企业解决了基础设施的问题,还能为小企业降低软件运维成本。一旦企业做大之后,也可以自建采用 OpenFaas 等开源方案解决 Serverless 的供应商锁定问题。 不论是 Node.js 后端应用还是 Serverless 应用,因为使用的是同一种语言,我们可以轻松地在前后端之间共享代码,可以是 Git submodule、NPM 包、远程等等的方式。 ## 引子 3:纯编译到 JavaScript 市面上有各种各样支持 compile to js 的语言、框架,诸如于 Kotlin.js、Scala.js、Python.js 等等。 对于小前端的应用来说,这种架构非常的不错。它相当于是渐进式的系统架构方案,当前采用了主流的前端框架,而非传统的后端渲染机制,并统一了技术栈,降低了组织内部的学习成本。不过,它带来额外的调试因素,毕竟每多一层封装,系统的复杂度就需要 * 2。 而为了让框架的使用者支持不同的框架 React、Angular、Vue,这个框架还需要提供这些框架的 bind 或者是 wrapper,以提升框架使用者的幸福感。 但是,我们的挑战依然是复杂的前端应用,以及它难以消除交互的复杂度。 ## 引子 4:共享领域模型/模式库 开始之前,我不得不强调一,领域模型是一种包含数据和行为的抽血模型。 编译到 JavaScript 是一种轻前端的方案,而对于重前端的项目来说,它们完成可以采用一种新的模式:共享领域模型。即将领域模型作为模式库,提供给前后端一起使用。即,我们只需要编译所需要的部分。 这在我使用了 Kotlin 的多平台技术(multiplatform)重写了 Chapi 的 domain 层之后,我意识到了这是一个非常迷人的方案。我即使用在前端代码中使用 Chapi 的领域模型,我还需要在后端的代码中使用这套模型。原先,我需要手动翻译一行行代码,现在我并不需要这样的一个步骤。只需要在 pom.xml、build.gradle 或者是 package.json 中引入依赖及其对应的版本即可。 在引入了这部分的代码之后,我们再关注于 UI 交互部分即可。 ## 引子 5:领域模型编译到 WASM 考虑到并非所有的语言都能支持 compile to JavaScript,一种颇为有效的方式就是使用 WASM。 > WebAssembly 或称 wasm 是一个实验性的低端编程语言,应用于浏览器内的客户端。WebAssembly 将让开发者能运用自己熟悉的编程语言编译,再藉虚拟机引擎在浏览器内运行。 —— [维基百科](https://zh.wikipedia.org/zh-cn/WebAssembly) 我尝试将使用 Go 编写的 Coca 编译成 WASM,但是遇到一系列的问题(我已经忘了),体积似乎是个问题,所以我尝试使用 Rust 去构建另外一种可能性。Rust 官方提供了 Rust Webpack Template,因此我可以将其集成到我现有的前端应用中。只是呢,似乎还没有人会使用 Rust 去编写后端应用。 但是 WASM 提供了一种更友好的方式,即我们不需要重写现有的代码,而是只需要添加一些代码,便可以将现有的后端模型代码提到给前端使用。并且,与混淆后的 JavaScript 相比,它看上去更加安全 —— 学习成本更高一些。 ## 引子 6:ComponentLess 在研究 Serverless 和微前端的期间,我突然有了一点想法,我对于客户端领域的 Serverless 式架构有了一些基本的构想,叫:ComponentLess。尽管有了一些基础的理念,但是还缺乏一个真实可用的 Demo,所以我并没有定义出什么是 ComponentLess。 起先,我以为无代码编程是一个 ComponentLess 方向,但是一研究发现并不是。无代码编程倾向于可视化编程,而 ComponentLess 倾向于使用 DSL 编程。就这一点来说,我便偏向于使用 Web Components + WAM 技术来构建新的前端架构。 ### ComponentLess 从单体应用转向微服务架构的一大特质是,组件(非单指 UI 组件,可以视为服务)由函数调用转向了 HTTP 调用。而 Serverless 进一步地将微服务的服务级别 HTTP 调用,细化为函数级别的 HTTP 调用。 对于前端领域来说,也是如此。微前端将单体应用拆分一个个的独立运行前端应用,我们可以随意地组合这些应用。进一步地,结合诸如于 Web Component 这样的组件级方案,便可以将拆分细分为到 UI 组件的粒度。我们可以使用 (HTML Imports 已遗弃)script 标签从远程导入: ``` ``` 因此,在未来,不论是前端开发人员,还是开发人员,都可以通过集成组件的方式来开发应用。也就是说,我们只需要关注于编写核心业务代码即可,剩下的部分可以通过一些特殊的方式来实现。 ### DSL 抽象化代码 ComponentLess + Serverless 是**代码即基础设施**开始的一个标志。当代码开始作为基础设施的一部分时,代码便需要以某种方式才能组合到一起。在 Serverless Framework 中,开发人员通过配置接入服务端所使用的基础信息。而 YAML 配置本身也是 DSL 的一种,缺乏灵活度,但是使用非常简单。 事实上,这是两个选择: - 配置 + 编程语言。 上手容易,迁移难 - DSL。 上手复杂,易于迁移 但是,无论如何我还是如何 DSL,它听上去有着更丰富的 KPI。至于如何抽象化基础设计代码,可以参考《[云研发:研发即代码](https://github.com/phodal/cloud-dev)》一文。 ### 模型复用 不论是 ComponentLess 还是 Serverless,它们都是由函数、UI 组件变为一个独立可运行的单元。为了与别人交互,它需要包含输入和输出。而输入和输出本身是需要一个数据模型作为支撑的,以此才能完成整个系统的稳定性。 而这个话题已经回到我们开头所讨论的内容里。 ## 前后端分离将死? 在所有的引子里, 我们已经准备了所有的论据,所以只需要: - 使用可以跨前后端的语言,构建领域模型 - 将后端服务、前端设施细化为更小的组件 - 设计 DSL 将领域模型转换到特定平台的代码 你就可以杀死前后端分离,就是这么简单。 前后端分离将死,不是现在,但是可能在五年后开始。 你说呢? ## 其它 架构,没有终点。

去年年底,在公司大佬的带领下,我们结合架构守护的需要,对代码进行了简单的建模。在过去的几个月里,我一直工作在相关的事项上,不断地优化、改进相关的模型:

说来惭愧,我并没有理由来再写这样一篇文章,因为答案大家都知道,只是呢,大家仍然都好奇 —— 或许大家是想找个合适的借口,以自我安慰;而不是成为努力的一个方向。

跨平台不是一个新的话题,它已经被讨论了几十年了。在最近的一些尝试,让我对跨平台有了一些新的想法。在想法真正落地之前,我梳理了一下不同跨平台方案的一些特征,便有了它的几种模式。

大概在五年前,我写了一篇文章《学习的艺术——如何学好一门技术、语言》,介绍了如何通过复写现有的系统来学习新的技术。而在最近的两次实践中,我发现了一种更高效(hard way)的方式来学习编程语言。因为高效(hard way),所以这并不是银弹。

来,一起用高效(hard way)的方式学习多种编程语言,Kotlin + Scala、Python、Go、Java、TypeScript、C#……

过去的一个月里,那些可爱的人还在辛苦的工作中,没有假期,有的人可能已经复工了两周 —— 比如归属于北京 ThoughtWorks 的同事,还有的人可能复工了一周 —— 比如归属于上海 ThoughtWorks,还有的还没复工 —— 比如归属于武汉 ThoughtWorks 的同事。

在过去两三个月里,我们的心情开始了各种跌宕起伏。每天我们不是在抢口罩、大米的路上,就是在抢推荐药物的路上。但是我已经 “分不清楚” 什么是真?什么是假? 我们离权力中心的距离,决定了我们离真相的距离。我们还在故事中,但是离主角很远,永远不知道真相是怎样的。 ## 过去与现在 所以,我想回过头看看历史,让我们看个我们能看的故事: - 1 月 8 日,朗普在发言中宣布,没有美国人在袭击中受伤或丧生。 - 1 月 22 日,美国中央司令部表示,11 名美国士兵在 1 月 8 日伊朗对伊拉克的导弹袭击后被确诊出了脑震荡 - 1 月 24 日,五角大楼发言人霍夫曼表示,受伤人数增加到 34 人。 - 1 月 29 日,美国国防部官方代表托马斯·坎贝尔对媒体表示,已经有 50 名美军士兵被诊断出在伊朗的导弹袭击中受伤 - 1 月 31 日,五角大楼网站的数据更新,显示有 64 名美军士兵在伊朗的报复性打击中受伤 我们都知道故事中很多数字不是真实的,但是真实的数字是多少呢 ?我们永远不得而知,因为在这个发生的过程中,我们看到的只是:**别人想让我们看到的**。 媒体都是掌握到权力的手中,再看个去年的故事: > 8 月 19 日,社交媒体公司推特、脸书相继宣布,删除、停用 936 个在中国内地创建的账号,理由是:它们有 “官方背景”,且有目的地涉嫌传播关于香港局势的涉暴 “假新闻”,破坏了所谓 “示威” 的 “合理性”。 最后,让我们再看个几年前的旧故事,标题也许就够了: > 《纽约时报》爆出食品业重大丑闻:美制糖业曾操纵科学家刻意误导大众 还是原来的配方,还是熟悉的味道。所以,还是民主社会有水平啊 (狗头)。 如果你熟知鸿蒙的开源模式,也许你也感到愤怒;中药也许是类似的,它们都是战略的一部分 『虚则实之 实则虚之』。你也都知道远水救不了近火,但是没办法,我们都是大众,只能被愚昧。 ## 整体看待问题 在节后的几天里,我刚好在看公司的技术雷达里推荐的《第五项修炼》,其中的『从啤酒游戏看系统思考』特别有意思。尽管,我因为种种原因,还没看完此书,但是我开始去拼凑所有的碎片。 双黄连是一个很好的安慰剂,兽用也是不错的,有助于平复民心。板蓝根和碘盐也是如此,换个角度来看,你面对着一群仓惶的民众,你并没有太多的选择。因为我们真的缺少太多的专业知识,我是一个程序员,你也是,我们都不是医生。 油和粮不够是一个阴谋,因为你不知道信息的真假,但是我们都知道**买了不会错**。所以,你天天和我一样要收到 10086 的通知短信,某某省油和粮是够的。于是,又回到了那个啤酒的故事。 天天早起抢菜的故事,有一天真的发生了。至于菜够不够是一个薛定谔,因为很多人一次性买了几天的量,导致了其它人没得吃。 …… 李医生敬职敬业,却 “死了两次”,而黑 + 会的人,拿了好处,却误国误民。 拾起你的勇气,试图去接着出事实的真实,而不应该只是《乌合之众》。 灾难就是一个放大镜。 ## 未来的过去 作为故事中的主角,但愿我们不会忘记历史: - 2003 年 SARS 事件 - 2009 年 H1N1 流感大流行 - 2019 年 2019-nCV 冠状病毒 接近真相很难,但是我们可以做的事情很多:保护家人。第三次面临这样的挑战,我才真正意识到我们对医学一无所知,我也对防护一无所知。在仓惶中,我们买了口罩但是也撑不了几天,没有买到酒精。 下一次哨声响起时,你是否准备好你的口罩和医用酒精。 下周就要上班了,你的口罩够吗?如果不够的话,你是不是想继续放假? 致敬奋战在一线的医务人员,致敬吹哨人。

对于技术债务,它的利息表现为系统的不稳定性,以及由于临时性手段和缺乏合适的设计、文档工作和测试带来的不断攀升的维护成本。

Feeds

RSS / Atom

最近文章

存档

2026 (1 月)
2025 (12 个月)
2024 (12 个月)
2023 (12 个月)
2022 (12 个月)
2021 (12 个月)
2020 (12 个月)
2019 (12 个月)
2018 (12 个月)
2017 (12 个月)
2016 (12 个月)
2015 (12 个月)
2014 (12 个月)
2013 (9 个月)
2012 (3 个月)
2011 (1 月)
2010 (1 月)
1991 (1 月)

分类

标签

作者