Blog
Blog
PHODAL

Viewing posts from 九月, 2019

你可能不需要微前端,但是需要一个胶水框架。

起先,我只是想写一篇如何提升软件质量的文章。后来在写质量文章的过程中,发现我还差一部分重要的内容没讲:依赖管理。于是,我着手准备写这篇文章,结果发现我还缺少一篇关于:依赖安全机制的文章——依赖孪生。所以,也就有了上一篇文章《依赖孪生:低成本的依赖安全方案》。 笑,为了安装好软件质量这个包,我已经陷入了依赖地狱了。 回到这篇文章,我们将介绍一些依赖管理的相关实践:从基础的依赖环境隔离到告别单体应用。 ## 1. 依赖的环境隔离 事实上,针对于不同项目、不同语言进行环境隔离,本不是这篇文章讨论的范围。但是,我们又不得不提及一些相关的内容。因为,我们总是习惯性也忘记了相关的内容。 由于不同的编程语言的包管理工具,存在对于依赖的 link 机制,所以对于它们的管理也稍有不同: - 全局统一依赖型语言的环境隔离。对于诸如 Python、Ruby 这一类脚本型语言来说,它们使用的是全局依赖,所以需要依赖于诸如 ``virtualenv`` 或者是 ``rbenv`` 为每个项目创造一个独立的运行时依赖环境。 - 项目独立的依赖隔离。对于使用 NPM 或者 Yarn 的前端开发人员来说,依赖存在于项目目录下的 ``node_modules``,自然而然地就进行了依赖隔离,但是需要对 Node.js 的版本进行限定。稍微一提,这种机制特别浪费硬盘。 - 包管理工具版本隔离。对于 Java 的 Gradle 来说,它稍有不同:统一的依赖存储路径,但是却不需要进行环境隔离,不过需要限定 Gradle 的版本。 - 其它。由于我的语言经验有限,暂时只有这些案例。 ``注``:由于经验有限,上述内容有些可能不太准确,如有有错误,欢迎指正。 总之,我们需要针对于不同类型的语言和包管理工具,采用与之匹配的有效的依赖环境隔离。 ## 2. 自建依赖创建 我们已经讨论了太多这方面的内容,这里就不详细展开了。 - 对于中大型组织来说,可以自建自己的依赖中心。 - 对于小型组织和团队来说,使用 Git 仓库也是一个不错的折中方案。 ## 3. 进行 LICENSE 扫描 对于依赖的 LICENSE 进行管理和风险识别,是依赖管理的一个重要的部分。除了常见的商用管理方案之外,我们还可以采用诸如于 Node.js 项目中的 https://github.com/mwilliamson/node-license-sniffer 或者是 https://github.com/3rd-Eden/licensing 都是一些不错的工具。 至于 LICENSE 选择的问题,永远都是 MIT 优先。 ## 4. 是否进依赖进行内联? 这是自 left-pad 事件之后,我采取的包的新策略(在我的开源项目上):对于小的软件包,直接复制源码,在项目中创建 ``third-party`` 放置相关的代码及 LICENSE。 这主要是结合了三个要素而考虑的: - 安全性 - 可迁移性 - 便利性(因人而异) 当然了内联依赖,涉及到一个版权问题——适合于代码少,不维护的项目。 ## 5. 依赖的协议隔离策略 除了内联之外,我们还要考虑的一个问题就是依赖的协议问题。 ### 策略1:再发布 当我们从 Google 上搜索代码的时候,往往会遇到代码在 ``gist``、``stackoverflow`` 或者 ``codepen`` 上,它们非常适合于我们复制到项目中使用,但是难免地可能会遇到一些版权问题。对于开源项目来说,可以直接在项目中使用,并进行标即可。而对于外部项目而言,一种最简单的方式就是二次发布这些软件包。 又或者是对于一些已经不维护的依赖包,而我们又需要,那么就只能在修改后二次发布这些软件包。 ### 策略2:二次协议 / 协议隔离层 对于 JavaScript / TypeScript 类库来说,在这方面的问题比较少,毕竟前端运行在客户端上,所以 Web 前端即『开源』。 如果真的非要使用某个开源软件,并且基于它之上修改,那么可以采取和 Android 开源协议类似的二次协议的方式。Linux 内核采用的是 GPL 协议,而 GPL 具有传染性——如果直接在 GPL 协议的类库上封装,那么只需要开源这部分的代码,因为认为我们的代码并不是衍生产品。而事实上 Free Software Foundation 动态地链接文件也产生了衍生产品,也就是说你用了 GPL 的库,你也需要开源你的代码。 为此,Android 系统在类库上采用的主要是 Apache-2.0 软件许可授权,对 GPL 进行了二次,它允许 Android 上的开发商基于 Android 的源代码进行开发而不向社区反馈。 所以,对协议进行隔离也是一个潜在可行方案,它从某种意义上将风险转移到了这一层级。 ## 6. 依赖更新机制 在日常的业务开发中,最痛苦的一件事莫过于:没有时间做技术升级,没有时间处理技术债。在这个时候,对于依赖更新这个问题,可能就会变得非常痛苦:你可能要亲眼目睹一个遗留系统的形成。所以,作为一个有责任的开发人员,你应该尽量去说服相关的人员,去做好相关的技术更新和升级。 除此,当依赖发现更新的时候,是否有相应的工具可以提供我们?一些现代化的工具,诸如于 Intellij IDEA 可以帮助我们更新依赖。也可以尝试包管理工具自带的升级命令,诸如于 NPM 中的:``npm outdated`` or ``npm outdated --parseable|wc -l``。不过大多数时候,我们可能会放弃升级——除非我们不得不升级。除此,https://david-dm.org 也是一个不错的工具——用于开源的公开 Node.js 项目。 相似的工具还有 [next-update](https://github.com/bahmutov/next-update) 是一个不错的更新工具。又或者是同一个作者写的 [next-updater](https://github.com/bahmutov/next-updater) 的工具。 ## 7. 版本选择?宽松型,还是严格型 在引入依赖的时候,我们需要稍微注意一个对于依赖的版本选择问题:到是宽松型,还是严格型。依赖的版本问题,主要会出现在**持续集成**和新成员加入项目。诸如于使用兼容发布条款,如 ~= 0.6.4,对于那些早期已经搭建了的开发来说,并不会有问题。而新的成员安装的时候,可能就变成了 0.6.5,在 API 上可能会发现一些细微的变化 。而诸如于使用 ``*`` 匹配版本的话,就更不严谨。 以 Python 语言中的 ``requirements.txt`` 为例,存在不同的描述版本的方式: ``` ~=: 兼容发布条款,如 ~= 0.6.4 等价于 0.6.* ==: 版本匹配条款 !=: 版本排除条款 <=, >=: 广泛的有序比较条款 <, >: 排除的有序比较条款 ===: 独断的比较条款 ``` 一些常见的情况如下: - 对于间断型维护的项目来说,往往选择严格型的依赖版本策略,因为大家都不想去碰了,哈哈。 - 对于长期开发的项目来说,选择宽松型的依赖版本策略,可以让项目可容易维护。 - …… ## 8. 使用依赖锁定 为了方便于在不同的开发人员之间能平稳地运行起项目,我们需要使用依赖锁定,以避免出现 DLL 地狱的问题。 > DLL 地狱(DLL Hell)指 Microsoft Windows 系统中,因为动态链接库(DLL)的版本或兼容性的问题而造成软件无法正常执行。 为此,我们需要依赖锁定配置文件,来记录已经安装的依赖的确切版本。除此,它还描述了生成的依赖树及其关系,以便于可重现安装依赖(即在后续的安装中能够生成相同的依赖树),而忽略依赖的更新。 依赖锁定配置与依赖配置的最大区别在于,依赖配置文件只描述了需要哪些依赖及期版本,而依赖锁定配置描述了依赖的子子孙孙依赖及期关系。 如我们的一部分依赖是在内部服务器,那么在安装的时候只会从内部服务器拉取相应的依赖,不会去外部环境下载。这个时候,我们所能做的是拷贝依赖,或者是删除这个文件,重新生成。与此同时,这个依赖锁定文件可以通过源码控制工具(如 git)来进行管理。 常见的锁定配置文件有,Ruby 中的 ``Gemfile.lock``,Node.js 中的 package-lock.json 或者 yarn.lock。无论你如何修改 ``package.json`` 的内容,它都会按照 ``package-lock.json`` 来安装依赖。 ## 9. 依赖代码安全检查 就目前来说,常见的有两种方式: - 商用解决方案。 - 依赖孪生机制。《依赖孪生:低成本的依赖安全方案》 笑~ ## 10. 告别大的单体架构 我的意思并不是说微服务好——不过真的很香,我的主要目的是想说:大的单体应用在依赖上存在着滞后的问题。 对于微服务来说,频繁更新的服务,必然可以做出依赖的及时更新;而对于基本不修改的服务来说,我们基本不会考虑去更新依赖。对于某一长期开发的单体应用而言,它们采用新的构架和编程语言非常困难。因为某个接口的修改,导致要修改一系列的代码,有可能相当于重写整个应用。 诸如于 Spring 框架本身一直在更新,而你正在使用的版本是 2.x,那么你可能与新版本已经不兼容。甚至于,需要维护自己版本的 Spring——出于更新漏洞的原因,你们重写了系统中的部分软件。 ## 11. == 什么是好的依赖 见下一篇文章。 参考内容:https://github.com/bahmutov/talks/blob/master/dependencies-best-practices-node.md

再三犹豫,终于在 rebase 到上海之后,还是决定写下这篇文章。三年多以前,我 rebase 到了深圳,开始了国内交付项目的旅途,我也几乎成为了待在该 account 下最长的 developer 没有之一。在那之前,我在 offshore 项目,混吃混喝混 session。

在阅读《零信任网络》的期间,我突然有了一个新的安全实施方案: 依赖孪生——针对于中小型 IT 组织的依赖方案。(PS:其实这只是吹吹而已,并没有那么夸张)。所以,我就顺手写了一篇文章,记录一下相关的实践和模式。

这里主要是指在 2019 年我看的一些不错的书,哈哈 ## 《零信任网络》 书的全称:《零信任网络:在不可信网络中构建安全系统》,英语:Zero Trust Networks: Building Secure Systems in Untrusted Networks 先介绍一下概念: > 零信任是一种安全模型,用于保护企业远离网络攻击并保护敏感数据安全。零信任扩展生态系统(ZTX) 包括数据和信息保护以及网络安全。 这本书介绍了一个理想的现代安全模型框架,包含了大量极具价值的实战经验。虽然,从某种意义上来说,它看上去更像是一本 DevOps / Ops 或者是信息安全方面的书籍,但是总的来说,我从中 GET 到了一些之前没有 GET 到的网络相关的知识。这本书从我们熟悉的 DMZ 区(Demilitarized Zone,隔离区)讲起,介绍了 DMZ 潜在的种种风险,进而引起了我对这本书的兴趣。 对于开发人员来说,有这么一点特别有意思: 本地认证解决方案。诸如于 UAF 标准,将信任从大量服务转移到——数量相对较少的用户可控的终端上。 值得关注的还有**倒数**第二章『零信任网络的实现』,介绍了如何去实现这么一个网络,并结合了 Google 的 BeyondCorp 的例子来展示。 ## 《架构整洁之道》 之前推荐过『《架构整洁之道》有感』,这里更新一下。 这本书是 Uncle Bob 的博客合集,所以这本书最吸、启发我的地方,怕是结尾的 《架构设计考古》相关的故事。编程年限时间越长,经常思考更好的解决方式,能收获到的知识也就越多。如果我们不能决定一个系统的架构,那么就思考、实践如何把它变好。过程中,大抵也是能收获更多的东西,对下一个系统有更多的启发。 第一、二部分,资深程序的程序员都会有一定的了解、实践。第三部分,是他最为人所知的 SOLID 原则,他最早出现 15 年前的《敏捷软件开发》等书上。而作为一个接受过 ThoughtWorks OO Bootcamp 训练的学员,我大抵还是能相当熟悉的运用它们。 第四部分,在讲述组件化架构,都是能以 UI 项目,而非后端服务谈论组件化架构,那倒能多得几分。终于在第五部分,开始总结性地介绍软件架构——这大概就是这本书最精彩的地方。除此,书中的这部分 Clean Architecture,经过我们的充分验证,这个架构模式对于大型项目来说确实不错——通过架构来规范代码。 然后,剩余的部分都在讲代码故事,Uncle Bob 讲述故事的能力,大概是我的好几个数量级。 说到底,还是因为我太年轻了,没能读懂这本书的精髓。看上去像可有可无的大道理,在落地上倒是得自己花时间去考虑。遇到一个架构方面的难题,带上这本书,加上所谓的悟性,或许我的问题就能迎刃而解。要是一看,本书倒是不适合初学者。可是,这本书的叙述方式,又相当的适合初学者。 ## 《演进式架构》 中文电子书已出版,中文纸质版正在出版中,英文名:Building Evolutionary Architectures 。 我关注我们公司几个大佬写的这本书很久了——从 2017 年出版的时间开始关注。虽然,我知道这是一本不错的架构书籍,但是我一直懒得(穷)看英语版。它和我过去关注的《浮现式设计:专业软件开发的演进本质》有一定的相似度,不过提出了更多优秀和可靠的意见和建议。 > 演进式架构是支持跨多个维度进行引导性增量变更的架构。 作为一本架构方面的书籍,它系统性的将我们所需要的要素整合起来: - **增量变更**。如何增量地构建软件和如何部署软件。 - **适应度函数**。架构的适应度函数为某些架构特征提供了客观的完整性评估。 - **适当的耦合**。如何确定哪些架构维度间应该相互耦合,以最小的开销和成本最大程度地获益。 《演进式架构》一书一直在强调一个观点,即**要长期的去规划架构**,架构是持续、迭代演进出来的。为此要时刻关注变化,添加演进能力,实施增量变更。 有意思的是,书中提到了我想要的另外一个答案:**可牺牲架构**——在概念验证成功后即被抛弃的架构(Martin Fowler)。换句话来说,在你实现 MVP(最小可行性产品)的时候,你可以用最快、最优的方式来实现系统,而非最适合的架构但是速度慢。 书中还提到了大量的架构反模式,诸如于:供应商为王——围绕供应商(如 ERP)构建架构、最后 10% 的陷阱——某些技术可以快速构建应用,但是无法完成最后 10% 功能(诸如于 React 的 CRA,也许你并不需要这 10%)、代码复用和滥用。以及陷阱:原始抽象泄露——底层抽象错误导致系统出现意外的灾难、**简历驱动开发**——不要为了架构而构建架构,构建架构是为了解决问题。笑~ (PS:这部分可能是这本书另外一个亮点,反正我觉得它非常精彩——就是案例不够丰富。) 书中最后一部分介绍了如何去实践演进式架构,哈哈哈。不过,这本书有一个问题就是写得太抽象了。以致于没有相关经验的情况下,可能有些地方难以理解——我也是听了公司的架构导读分享之后,才对这本书有了一个更新的认识。 ## 《数据密集型应用系统设计》 这本书我是在公司的邮件里,看到同事的推荐买的。反正,O'Reilly 的动物书不会太差。买完之后,发现这本书相当的不错,又弥补了我缺少的一些知识点。在写这篇文章的时候,我意识到这么好的书,在豆瓣上应该有很好的评分——果不其然,评分 9.7 (187 人评价)。 这是一本不可多得的关于数据方面的好书——特别是对于缺少数据方面的开发来说,比如非科班出生的程序员。不论你是前端工程师,还是后端工程师,或者是 DevOps 工程师——只要你是个工程师,都建议你去读一读。 书的第一部分是数据系统相关的基础部分。这部分的内容非常棒,它整理了一系列关于数据模型与查询语言、 数据编码与演化、数据存储与检索相关的知识。它是一个相当不错的知识索引和概括,帮助你重新梳理数据系统相关的整个体系的内容。**哪怕是你对分布式系统没有兴趣,你也应该读完一章**。 书的第二部分是**分布式数据系统**,也就是我们在各种讲后端架构常会看到的内容。也因此,这一部分的内容对于后端来说,它会更加有价值——诸如于各种分布式系统的基本问题,以及对应的解决方案。 书的第三部分是**派生数据**,包含了『批处理系统』、『流处理系统』以及『 数据系统的未来 』三个章节,我还没看……。因为关于批处理和流处理相关的内容,我已经有了一些实践。而且相关的内容,并非一两个章节能讲完的,笑~。 不得不提及的是,这本书每一个章节的结尾处都有几十个、几百个引用——我的意思不是说,这本书在浪费我辛辛苦苦赚的钱,而是这本书真的很细致、严谨。 ## 《前端架构:从入门到微前端》 经过无数次的微信群聊证明了:这本书是一本给前端的装逼利器。它可以用于打击绝大部分的后端开发人员,无往不利。笑~ 你需要前端微服务,这里有。你需要前端的规划,这里有。你需要更好的前端架构,这里有。 ## 其它 综上所述,你应该**优先看**《零信任网络》第一、第七和第九章,《架构整洁之道》的第 5 部分,《数据密集型应用系统设计》 的第一部分,《演进式架构》的第六和第七章。对了,还有《前端架构:从入门到微前端》全书,笑~。 不过,适合我的不一定适合你,但是多读书总是没错的。

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 月)

分类

标签

作者