邹城市建设银行网站,快速做网站流量数据统计分析,wordpress 生成pdf,做网站的专业叫什么工程师如何对待开源
本文是笔者作为一个在知名科技企业内从事开源相关工作超过 20 年的工程师#xff0c;亲身经历或者亲眼目睹很多工程师对待开源软件的优秀实践#xff0c;也看到了很多 Bad Cases#xff0c;所以想把自己的一些心得体会写在这里#xff0c;供工程师进行…工程师如何对待开源
本文是笔者作为一个在知名科技企业内从事开源相关工作超过 20 年的工程师亲身经历或者亲眼目睹很多工程师对待开源软件的优秀实践也看到了很多 Bad Cases所以想把自己的一些心得体会写在这里供工程师进行参考希望能帮助工程师更好的成长。
概述
作为一个在科技企业内部进行技术工作的工程师工作任务就是用技术手段支持和实现公司所关注的商业目标。 实际工作过程中需要主动或者被动的使用和维护大量的开源软件。 据统计每个工程师在企业内部进行研发和运维等工作的时候每年会接触到上千款开源软件 如果是以 Java 或 JavaSciprt 为主要程序开发语言的工程师则接触到的开源软件数量更多在万级别甚至十万级别。 数据来源《2020 State of the Software Supply Chain》由 Sonatype 发布
那么如何选择开源软件 这么多开源软件中如何根据个人需求和业务需要来选择合适的开源项目来进行投入是需要综合考虑的。
选择了开源软件之后又如何进行定制和长期维护 这也是一个很大的问题。因为在企业内部开发软件跟个人开发软件不一样的是维护一个计算机软件系统的成本远远大于开发该系统或软件的成本。选择开源软件之后如何从长期的视角进行定制和修改后续的长期维护如何进行才能做到高效和节省成本业内有很多很好的经验也有不少不太成功的案例成为教训。
最后回到个人工程师的成长是在不断的学习和实践中进行的。如何来利用开源来提升自己能力扩大自己的眼界提高自己技术口碑和业内影响力对于工程师本人也是非常重要的。
本文将从如下三个部分来分别阐述
工程师如何选择开源软件工程师如何定制和维护开源软件工程师个人成长如何利用开源
1. 如何选择开源软件
首先要明确对开源软件的态度在现阶段是不可能离开对开源软件的使用的。 使用开源软件有各种各样的风险包括开源合规、安全、效率的问题。 简化为一句在企业内部使用开源软件需要遵守该企业对开源软件的内部规定包括如何引入和如何维护以便达到高效、安全、合规的使用。
回到具体如何选择特定的开源软件的问题上有如下几个纬度可以进行参考。
根据需求根据技术发展趋势根据软件采纳周期的不同阶段根据开源软件的成熟度情况根据项目的质量指标根据项目的治理模式
1.1 根据需求来选择开源软件
选择开源软件首先要明确需求即选择这个开源软件的目的究竟是什么。 工程师选择一个开源软件究竟是它用来做什么的是用来进行个人学习的 还是用来满足 ToB 客户的需求的还是用来满足内部服务开发的需求的。 这三个不同的目的下选择开源软件的导向完全不一样。 注意后两个场景是需要先考虑企业开源合规的需求的参见第三章
先说说选择开源软件来进行个人学习那么需要看看个人学习的具体目的究竟是什么。 是想学习一种比较流行的技术来完善个人的技术知识结构扩大个人技术视野还是想看看相应的开源技术项目的具体实现来作为内部项目技术开发的参考还是想为了下一份工作进行有针对性的技术准备。不同的目的会导致不同的选择。针对前者显然是什么技术最流行选什么自己缺什么选什么针对第二种目的一般是对该技术领域的知名开源软件或者创新性软件进行有针对性的选择即某个特性是我当前需要的或者是我当前项目实现不好的我需要看看别人是如何实现的。最后一种显然是按照下一份工作的职位需要和技术栈要求进行准备并根据技术栈要求的门槛高低进行选择。但是注意从个人需求出发选择开源软件一般都需要写个小项目练练手比如一个 Demo 程序或者一个测试服务因为不用考虑后续的长期维护所以尽可以按照个人的想法和个人研发习惯进行各种练习不用遵循企业内部的开发流程和质量要求也不用考虑该开源软件的稳定性和社区成熟度等情况只需要尽情的学习和参考代码就好了。
然后看下一个需求选择开源软件进行研发的软件是需要提供给客户的往往可能还是以私有云的方式进行交付。基于此类需求来选择开源软件注意作好平衡即客户的需求和企业自身技术规划或产品的长期规划需要。以私有云方式进入客户的 IDC 环境是需要跟客户开发和运行环境的上下游项目进行集成的。这时候要看客户的需要可能某些客户对开源软件有特定的要求例如要求使用 HDFS 而且是某个特定版本。对这类指定软件名字和指定版本的要求有可能是因为客户当前比较熟悉这个版本也有可能是因为之前其他软硬件供应商提供的软件和版本指定的目的是方便集成和后续的使用与维护。如果这种需求是符合企业项目或者产品的长期发展需求的则是可以完全满足的。如果甲方非常强势除了满足他的要求之外没有别的办法那就选择客户所指定的软件和版本好了。但是如果跟自身项目或产品的长期发展需求不一致而且具体项目或者版本是可以跟甲方进行协商的那么需要跟客户协商出一个双方都能接受的结果出来即选择特定的开源软件和版本既要做到客户满意并买单又要做到自身的交付成本可控还要做到符合自身项目或者产品的长期发展需要。例如客户使用 Java 的某个老版本但是企业的 toB 交付的软件要求使用 Java 的较高版本。那么需要跟客户协商要么切换到企业希望的版本上还需要帮助客户完成已有系统的升级工作要么只能降低自身软件的 Java 版本需求可能还需要对某些自身代码进行修改还可能对软件中的某些依赖组件进行修改。这个场景下是带有很多客观约束条件下的选择是需要跟客户自身的产品经理和架构师一起协商的。
最后如果场景是为了满足内部服务的需求即选择开源软件来搭建的服务是给内部业务或者最终用户来使用的常见于国内各大互联网公司的互联网服务系统和各种手机上的 App。这时候项目的开发和维护方有较大的自主权跟 toB 的交付业务完全不一样。此时选择开源软件就一定要综合考虑开发和维护成本还要考虑使用该服务的业务所处的阶段。
1如果提供的服务是给创新业务使用的创新业务一般都是试错业务随时需要根据市场情况的变化和当前执行的状态进行调整很可能三个月后这个项目没了即被取消了。这种情况下 “糙快猛” 的开发方式是比较合适的不用太多考虑系统的可维护性和可扩展性就用研发团队最熟悉的软件技术栈然后用底层技术支撑团队比如基础架构团队提供的成熟而且经过验证后的底层基础技术平台就可以最重要是尽快把系统搭建出来然后随着产品进行快速的迭代。这个时候需要尽量降低现有研发运维团队的学习成本和开发成本不用太多考虑可维护成本因为需要糙快猛的把系统堆出来验证产品需求和商业模式是最重要的时间最重要。如果发现有市场机会就快速跟进站稳脚跟之后可以采用省时间但是费资源的方式俗称 “堆机器”来进行扩展或者采用 “边开飞机边换引擎” 的模式进行重写都是比较划算的。对于处于创业阶段的企业或者项目来说速度胜过一切。
2但是如果选择开源软件搭建出来的计算机软件系统或者服务是需要长期维护的比如是给公司内成熟业务使用的或者是针对公司内成熟平台的缺点进行系统升级并要替代原有产品的那么在满足业务需求的前提下考虑系统的可维护性变成最重要的事情。选择对应的开源软件它是否成熟是否稳定二次开发是否友好运维成本是否比较合算即比较省机器和带宽运维操作是否方便例如常见的扩容和缩容操作是否可以高效、自动、无损的完成Upstream 到上游开源社区是否容易等等这些都成为需要重点考虑的事情。这种情况下开发一个系统的成本可能只占整个系统生命周期内的成本的 1/10 不到。所以在满足需求的前提下重点考虑可维护性。
1.2 根据技术发展趋势来选择开源软件 如上图所示现代计算机软件或者服务的研发是一个不断运行的循环和迭代过程。从市场分析开始然后进入到创意阶段再到编码阶段最后到上线阶段完成应用的部署和生效上线之后根据得到的数据反馈继续进行分析。这个循环迭代的过程显然对于一个身处竞争激烈的行业的企业来说迭代的速度越快越好同时也需要具备快速弹性、低成本伸缩的能力即产品方向对了那么赶紧进行系统扩容承接快速增长的流量做到快速增长如果产品方向不对需要赶紧缩容把相关硬件和人力资源节省出来投入到新的试错方向上去。身处同一个行业内的企业如果企业 A 能以更低的成本更快的速度的进行各种产品和策略的迭代显然它是能比迭代速度慢成本高的企业 B 是有更好的竞争优势的。
现在的开源软件数量非常多几乎每一个分类下面都有很多的开源项目。针对某一个具体的需求如何进行选择一个建议是根据技术趋势进行选择。即现在的计算机系统迭代的方式是 Agile敏捷 Scale扩展。显然能够支持计算机系统进行快速迭代并能够很方便进行低成本弹性伸缩的开源软件是值得进行长期投入的。而对一个新的开源软件的学习和使用学习者是希望该软件的学习门槛越低越好。一个流行的开源软件内部实现可以尽可能的复杂但是对于用户来说一定是需要用户友好的。不然即使创新度再好易用性不好只有极客才能学习和掌握创新的鸿沟是很难跨越的。
例如 Docker 的出现之后以极快的速度风靡全球非常多的工程师喜欢上了 Docker。就是因为 Docker 的特性在传统的容器系统之上增加了新特性包括把应用程序和底层依赖库封装为一个容器镜像容器镜像有版本而且可以通过集中的镜像仓库进行存储和大批量分发。Docker 首先解决了长期困扰工程师的开发、测试、上线环境标准化的问题能够支持开发者进行快速的迭代。同时使用了统一的镜像仓库来进行镜像的分发而且底层采用了轻量级虚拟机即容器的技术可以非常快的被拉起所以采用 Docker 的系统可以很方便的进行弹性扩展。同时因为把应用 App 封装在一个镜像里面可以在逻辑上根据 Domain Model 的设计原则进行更好的抽象和复用。显然这样的技术是值得每一个开发计算机系统的工程师学习和掌握的。因为他能带来极大的方便。相反在 Docker 产生之前虽然 Control Group简称 cgroup Namespace 的技术早就已经出现并早就集成在 Linux 内核中Google 的 borg 相关的论文早就已经发表但是一般的技术研发团队不是很容易就能驾驭容器并把容器系统在公司内部大规模进行部署的。印象中 borg 论文出现后国内只有 BAT 级别的互联网公司才有一小撮精英研发团队来研发和使用容器管理系统例如百度负责 Matrix 系统研发的团队阿里负责 Pounch 系统研发的团队腾讯也有一个小团队负责容器系统的研究。但是除了那一小部分团队更多的工程师因为相对较难的学习难度而没有把容器大批的用起来。而 Docker 这种技术就是非常好的顺应了敏捷和弹性扩展的技术趋势而且提供了非常好的用户易用性然后一出场就被非常多的工程师迅速使用上了而且成为市场的默认标准。
这些顺应潮流的开源软件是值得选择和投入的。
另外一个例子是 SparkSpark 的出现解决了 MapReduce 在分布式计算过程中因为需要频繁进行 IO 操作导致的性能比较低下的问题同时在易用性上有较大的提升所以才取代了 MapReduce 在分布式计算领域内的主流地位。
1.3 根据开源软件采纳周期的不同阶段进行选择
软件作为智力活动的产物他有他的生命周期一般用软件的技术采纳曲线表示。
开源软件也是软件的一种也都是遵循软件的技术采纳规律的。如下图所示 一个开源软件从创建到衰亡一般会经过 5 个阶段。 从创新期Innovators占比 2.5%到早期采纳期Early Adopters占比 13.5%然后跨越鸿沟chasm进入到早期大众期Early Majority占比 34%再进入后期大众期Late Majority占比 34%最后进入衰退期Laggards占比 16%。绝大部分的开源创新项目没有能成功的跨域鸿沟即从早期采纳阶段进入到早期大众阶段就消亡掉了。 所以如果是选择一个需要长期使用并维护的开源项目选择处于早期大众或者后期大众状态的项目是比较理智和科学的。
当然如果只是个人想学习一个新的东西可以看看处于创新者状态的开源项目或者看看处于 “早期采纳者” 状态的项目。
注意不管是从长期研发系统的角度还是从个人学习的角度都不要再去看处于衰退期Laggards的项目了。 例如现阶段即 2022 年是不用再去选择 MesosDocker Swarm 之类的项目了。自从 Kubernetes 成为容器调度技术分类的默认标准这两个项目就已经处于衰退期他们的母公司都已经放弃了。这个阶段如果还投入较多精力来开发和维护除非真的是非常强势的甲方要求把钱砸在工程师面前逼的不得不用才会选择。
同学们可能会问从哪里可以看到这些技术采纳度曲线
InfoQgartnerthoughtworks 每年都会更新他们各自的技术采纳度曲线并公布出来 大家可以在网上搜索一下看看他们各自的技术采纳图是什么然后结合一些业内的经验得出自己的判断。
例如 https://con.infoq.cn/conference/technology-selection?tabbigdata
从这里能看到 2022 年 InfoQ 对 BigData 领域各种流行技术的判断。 从上图可以看出Hudi、Clickhouse、Delta Lake 等开源软件还处于创新者的阶段即在工业界采纳还比较少对于想学习新项目的同学是可以重点关注的。但是现在这些开源软件还不适合应用在需要长期维护的成熟应用场景里面。
注意这些知名科技媒体的技术采纳曲线是每年都在更新的在进行参考的时候别忘了注意一下发表的时间。
1.4 根据开源软件的成熟度情况选择开源软件
还有一点即根据开源软件本身的成熟度来选择开源。 即从这个开源软件是否定期发布是否处于一个多方维护的状态即使一个公司的战略发生了变化不再继续维护了还有其他的公司在长期支持是否文档比较齐全等多个维度来进行成熟度的评估。
对于开源软件的成熟度模型开源社区有很多度量开源项目的成熟度模型其中 Apache 开源软件基金会的项目成熟度模型是比较有名的。
可以参考这里 https://community.apache.org/apache-way/apache-project-maturity-model.html
按照这个 Apache 开源软件基金会制定的开源项目成熟度模型他把一个开源项目的评估纬度分为 7 个维度
Code代码License and Copyright软件许可证和版权Release发布Quality质量Community社区Consensus Building共识共建Independence独立性
每个纬度又有几个考察项。例如针对 Independence独立性又有两个考察项其一是看这个项目是否独立于任何公司或者组织的影响其二是看贡献者在社区内活动是代表他们个人还是作为公司或者组织的代表出现在社区并进行活动的。
Apache 基金会 Top Level 的项目即顶级项目在毕业阶段都会从这些维度进行综合的判断。只有各方面都达标的项目才会被允许从 Apache 基金会的孵化状态中毕业而成为成为 Top Level 的项目。这也是逼着个人比较喜欢 Apache 顶级项目的原因。
另外OpenSSF 项目的 Criticality 评分参见 https://github.com/ossf/criticality_score也是一个不错的参考指标它会度量一个项目的社区贡献者数量、提交频度、发版频度、被依赖的数量等指标来判断一个开源软件在开源生态中的重要程度。这里就不详细展开了有兴趣的同学可以参考它的资料个人认为是一个值得参考的方向但是这个评分还处于早期阶段距离理想状态还比较远。
1.5 根据项目的质量指标来进行选择
很明显有些开源软件的代码质量是比其他开源软件的质量好。 有的时候需要从项目的质量情况来选择开源软件。
这个时候我们需要查看一些被业内广泛证明比较有效的指标。
其中 MTTU 是被知名开源供应链软件供应商 SonaType 所推荐的指标。 它在它著名的供应链年度报告里面提到 MTTU。 参见 https://www.sonatype.com/resources/state-of-the-software-supply-chain-2021
MTTUMean Time to Update即开源软件更新它依赖库的版本的平均时间。举个例子来说某开源软件 A 依赖于开源库 B假设 A 的当前版本是 1.0依赖 B 的版本是 1.1。某天开源库 B 的版本从 1.1 升级到了 1.2然后一段时间之后开源软件 A 也发布了新版本 1.1其中把对 B 的依赖版本从 1.1 升级到了 1.2。这个时间间隔即从开源版本 B 的版本升级到 1.2 的时间点距离开源软件 A 的新版本 1.1 的发布时间称之为 Time to Update反映出来的是开源软件 A 的研发团队根据依赖库的更新周期同步更新它的依赖版本的能力。Mean Time to Update 是指这个软件的平均升级时间。数值越低表明质量越好表明该软件的负责人在很快速的升级各种依赖库的版本在及时修复各种依赖库引起的安全漏洞问题。
据 SonaType 的统计业内开源软件的更新升级时间 MTTU 越来越短。 据它的统计在 Maven 中心仓库上的 Java 类开源软件2011 年平均的 MTTU 为 371 天2014 年平均的 MTTU 为 302 天2018 年平均的 MTTU 是 158 天而 2021 年平均的 MTTU 时间是 28 天。能看出来随着开源软件库更新频率的加快使用它们的软件也随着加快了更新版本的速度MTTU 相对 10 年前时间缩短到原来的 10/1 以下。
当然 MTTU 只有项目质量的一个间接纬度。 历史上是否爆出重要高危安全漏洞修复响应是否快速及时等等也是作为开源项目质量评价的重要维度。
某些大厂的安全部门会不断评估开源软件的安全情况把某些屡屡发生高危安全漏洞但是修复不及时的开源软件设定为不安全软件列入到内部的开源软件黑名单中对内公示并要求各个业务研发团队不再使用这些软件实在因为研发和人力问题不能迁移到新的软件系统的情况也需要把这些老服务迁移到一个相对封闭的网络环境中减少风险可能造成的损失。这个时候显然应该需要遵守公司的安全规定不再使用黑名单上的开源软件。
1.6 从开源软件所属于的开源社区治理模式角度来考虑。
还有一个维度即从这个开源项目的社区治理模式来考虑适用于需要长期进行开发和维护的项目。
社区治理模式Governance Model主要是指该项目或者社区是如何做决定的以及由谁来做决定。 具体表现为 是所有人都可以做贡献吗还是少数几个 决定是通过投票的方式产生的还是通过权威计划和讨论是否可见
常见的开源社区和开源项目的治理模式有如下三种
单一公司主导特点是软件的设计、开发和发布都由一个公司来控制也不接受外部贡献。开发计划和版本计划不对外公开相关讨论也不对外公开版本发布时候才对外公开源码。例如 Google 的 Android 系统。独裁者主导有个专有名词 “Benevolent Dictatorship”翻译为 “仁慈的独裁者”特点是由一个人来控制项目的发展他有强大的影响力和领导力一般都是该项目的创始人。例如 Linux Kernel 由 Linus Torvalds 来负责Python 之前由 Guido Van Rossum 来主导。董事会主导特点是有一拨人构成项目的董事会来决定项目的重大事项。例如 Apache 软件基金会的项目由该项目的 PMC 决定CNCF 的基金会的决策是 CNCF 董事会来负责很多技术决定授权给了 CNCF 董事会下的技术监督委员会。
个人意见和经验根据该开源软件背后的开源社区的治理方式来进行选择优先级的排序如下
优先选择 Apache 毕业项目因为这些项目的知识产权情况清晰而且至少有三方在长期维护次优选择 Linux 基金会等其他开源基金会的重点项目因为 Linux 基金会的运营能力很强每个重点项目后面往往都有一个或者多个大公司在支持小心选择一个公司主导的开源项目因为该企业的开源战略随时可能会调整很有可能不再持续支持该项目例如 Facebook 就是一个弃坑很多的公司尽量不选择个人开源的项目个人开源更加随意风险尤其高但是不排除某些已经有很高知名度并且跑出长期维护模式的项目例如知名开源作者尤雨溪Evan You所负责的 Vue.js 开源软件。
这是个人推荐的选择同类开源软件项目的优先级顺序仅仅代表个人观点欢迎讨论。
2. 如何定制和维护
把一个开源软件引入到企业内部后并用来进行开发和长期维护就出现了如何定制和维护的问题了。 首先要明确开源软件引入到企业内部之后是需要定制的。 因为如下几个理由
开源软件往往都是适用于通用场景考虑的情况比较多需要支持各种各样的使用场景。但是引入到企业内部之后往往只需要针对企业特定的场景。所以针对这些特定场景进行优化例如对全部功能进行剪裁去掉跟本场景无关的特性针对特定场景进行性能调优和参数优化等往往能取得更好的性能例如可以抗更多的流量节省机器成本的效果是惊人的。这也是常见的定制方法。开源软件进入企业内部要经过开发并长期运营是需要满足该企业的各种内部的服务运维规范的。例如业务上线是需要有完整的日志和监控比如需要提供服务健康检查接口还需要有流量调度等容错处理。这些都是需要进行定制修改的。开源软件还需要对接企业内部的上下游系统例如如果该软件的正确运行需要依赖底层的分布式存储和分布式计算系统来完成基本功能是需要对接企业内部已有的存储系统或者计算系统的企业内部的底层虚拟机系统或者容器调度系统往往有部分修改和优化对接起来也是需要进行修改的所以这个时候需要进行定制修改。特殊场景下的需求定制在企业应用场景下使用该开源软件往往会遇到特定的问题可能会碰到 Bug这些都需要 Bugfix 和新增特性来支持。
2.1 如何对开源软件进行定制和修改
对此笔者建议有几个基本原则 不动开源软件的核心代码尽量使用该开源软件已有的插件机制或者在外围改定期升级到开源社区的稳定版本。
很多开源软件在设计之初就留下了不少扩展机制方便后续开发者进行功能扩展和特性增加。例如几个最著名的开源软件 Visual Studio CodeFirefox Browser 就提供了 Extension 机制很多开发者根据自身需求开发对应的插件并把插件提交到官方支持的插件市场里面。普通用户在安装完成主要程序后还可以浏览插件市场寻找和选择自己需要的插件进行安装。 另外像 Kubernetes也在多个地方提供了扩展机制例如核心调度器哪里提供了定制化的 scheduler可供开发个性化的调度策略底层的存储和网络都提供了很多的插件机制最值得称道的是它提供了 CRDCustom Resource Definition的机制允许开发者定义新的资源类型并复用 Kubernetes 成熟的声明式 API 和调度机制进行很方便的操作和运维。 所以尽量使用该开源项目已有的插件或扩展机制来增加特性。
针对某些开源软件的修改和定制并不太适合使用它的扩展机制或者它本身没有提供可用的扩展机制。这个时候的修改尽量在源码核心的外围进行修改而不要去动它的核心代码。因为开源软件是随着开源社区的进展不停的迭代的开源社区的发展会不断带来更多更好的特性。如果对核心代码进行了修改而当需要升级到比较新的开源版本的时候就会非常的痛苦。因为有大量的内部 Patch 需要进行合并而且需要各种测试会导致升级成本过高而无法跟社区的主要版本进行同步最后因为部分核心工程师的离职或者转岗那部分的修改没人能持续维护下去导致整个系统无法维护和升级最后导致整个系统被废弃或者被推倒重来这会导致大量的人力成本。笔者在多家互联网大厂工作过很多年看到了太多这种项目太多本来针对开源项目的修改是非常有必要的但是因为改动了核心代码导致想升级到开源社区的较新版本成本太高最后导致系统无人能维护只好推倒重来的例子了。
举个例子吧笔者在某大厂内部看到有两个技术团队在维护 Redis 集群当时使用的版本都是 Redis 2.x 版本。因为没有太多集群功能对大规模的业务支持不好所以这两个团队都对 Redis 的 2.X 版本进行了修改。其中团队 A 的改法是在外围改即在 Redis 之上封装了一层用来进行流量调度Failover 处理等功能团队 B 就改的狠一些直接改 Redis 的核心代码把集群功能相关的代码直接加了进去甚至在某些局部测试场景下性能更好一下。短时间内两个团队都能满足业务线的需求。但是 Redis 开源社区在不停的迭代不断加入更多更好的需求当 Redis 出到 3.x 的时候两个团队都想升级到比较新的版本因为使用 Redis 的业务方也希望使用 3.x 的版本。但是升级成本明显不同团队 A 很快把相关功能移植到了 3.x 之上很快把 Redis 版本升级了上去团队 B 呢因为对核心的改动太大移植成本和测试成本都太高所以迟迟不能对 2.x 版本的服务进行升级。等到社区 4.x 版本出来团队 B 的核心工程师离职之后该 Redis 集群已经没有人能够持续维护并满足客户的新版本需求只好推倒重来从社区的 4.X 版本直接建集群自身的系统迁移化了很长时间也给客户带来了很多成本。
所以对开源软件源码的修改都建议以 Local Patch本地补丁的方式存在一来便于进行维护和升级二来也方便管理和统计。这种模式下内部项目的编译脚本一般都是把该开源软件的某个源码包解开然后通过 patch 命令把这些 Local Patch 一一打进去之后再一起进行编译和测试。而不是把 Patch 直接打到业务源码里面虽然在 CI 阶段省了几分钟但是后续的维护、升级、管理却增加了相当的麻烦。
2.2 回馈社区Upstream回馈到上游开源社区减少维护成本
工程师在企业内部针对某个开源软件的某个版本进行功能特性的增加或者 Bugfix 之后一般会以 Local Patch本地补丁的方式存在在代码库中。笔者建议工程师在解决完业务问题之后尽量把这些 Local Patch 提交到该开源软件所属的上游开源社区里面去完成 Upstream 的过程。
Upstream 有如下几个好处
能获得更好的代码
在企业内部针对某开源软件增加特性尤其是 Bugfix 的补丁往往因为时间紧急更多采用的是 “Hack” 的方式即为了快速上线解决问题补丁修复的地方不一定很合理代码补丁的逻辑可能会有漏洞代码补丁可能对更多异常条件的处理不够完善等等。这个时候如果把这个 Local Patch 提回到该开源项目所属的开源社区里面跟该开源社区的资深工程师Module Reviewer/ 模块负责人等进行深入的沟通交流之后往往会根据他们的反馈对代码补丁进行更好的完善从而能得到更好的代码。
能减轻维护成本
内部保留的 Local Patch在每次升级到开源软件较新版本的时候这些 Patch 都是需要进行评估部分需要和入并测试的。当然希望这些 Local Patch 的数量越少越少。最好的办法就是当该开源社区发布新版本的时候就已经包含了这些 Patch。包含的数量越多企业内部需要评估、需要合并和测试的 Local patch 数量就越少升级起来成本就越低。记得 Fedora 的发布版本里面每个版本都保留了不少针对内核和其他组件的 Local Patch红帽的工程师也在不断的把这些 Local Patch 贡献并和入到上游开源项目社区里面这样才能保持 Fedora 内部的 local patch 数量在一个比较低的水平也保证了升级版本时候的成本是比较可控的。
建立团队技术品牌和雇主品牌方便招聘并提升工程师自豪感
向上游开源技术社区贡献代码Upstream 这些 Local patch是可以获得更好的社区口碑的。向这些技术社区表明该公司不仅只是开源软件的消费者同时也是贡献者。
同时可以建立起较强的团队技术品牌表明该公司不仅仅业务比较不错技术团队也是很有实力的这样方便对外招聘。
Upstream 到上游开源社区同时也有利于提升团队的工程师自豪感和满意度。
举个例子 小米公司在大量使用 Apache HBase 项目的时候负责的研发工程师坚决执行 Upstream 的策略不断的把小米内部验证过的 Patch 贡献回到 HBase 社区并和 Hbase 社区的同学们一起进行某些特性的讨论和研发。小米同学在 HBase 社区的影响力越来越大不断产生了 Committer 和 PMC最后小米工程师张铎成为该项目的 PMC 负责人即项目的 PMC Chair。小米公司在大数据、云计算等领域的技术品牌很大程度上来源于此项目相关的研发团队。
3. 个人成长如何利用开源
工程师的成长跟他从事的日常工作密切相关也跟他的日常学习密切相关。 在这个过程中如何利用开源软件来更好的帮助工程师进行成长帮助工程师实现他们的职业理想或者技术理想 这里有一些建议。
3.1 开放和共享眼界和心态
站住巨人的肩膀上才能站的更高。 开源世界里面有的是各种各样的软件面向各种场景解决各种问题。 所以一定要保持一个开放的心态即在做什么技术相关的事情之前先看看别人是怎么做的。 要知道世界这么大工程师遇到的问题 99.99% 以上都是别人已经遇到的问题别人是如何解决的有什么经验可以学习 尤其是可以看看别人开源出来的项目看看他们的设计文档看看他们是如何思考的看看他们的源码看看他们是如何实现的。 如果感兴趣还可以进一步跟他们直接交流。 一来可以少走很多弯路避免很多不必要的重复工作避免重复踩坑。 二来不用重复造轮子可以把有限的时间放在更有价值的工作上去。 千万不要坐井观天老子天下第一多看看工业界和开源界刚毕业去大厂的同学尤其需要注意。
另外还需要共享的心态学到了最好能共享出来 让别人也能参考吸取经验和教训从而达到共同提高的目的。
3.2 学习开源软件的推荐步骤和方法 — 费曼学习法
学习开源软件有各种学习方法。 针对不同的学习目的也需要根据自身情况即对该领域的熟悉程度以及对相关开源项目的了解程度等采用不同的更适合自身的学习方法。
笔者在这里给大家推荐一个适合工程师学习一门全新的开源技术项目的方法
先尽快入门把这个开源软件的 Quick Start快速入门和 Tutorial入门教程跑起来先了解它的主要场景和关键特性。然后看文档注意系统的主要架构图了解整个系统的大致架构建立起一个比较大的整体框架图出来。最后再结合自身的实际应用场景看相关细节包括某个细节的文档和代码。
比如如果想学习 Kubernetes先上它的官网把它官网上提供的教程快速运行一遍 (https://kubernetes.io/docs/tutorials/kubernetes-basics/create-cluster/cluster-interactive/) 了解如何创建 pod如何访问如何更新如何进行流量调度等等。 然后看它的架构图了解它的设计原则即声明式编程包括几个核心组件 Kube-apiserverkube-scheduler,kube-controller-manager, kubelet 等的功能以及这些组件都是如何交互的 最后再根据自身的业务场景需要看看具体哪部分还需要更深入的了解。 例如需要加入自己的存储方式那么看看相关的代码参考其他友商的存储方式的实现。
不建议一上来先捧着源码看这么看是没有头绪的而且效率很低。 况且现在不少开源项目都 Too Big 了而且迭代速度很快很难有人能了解全部代码而且从个人精力来说做不到更别说也没有必要。
注意学习一定要和应用结合起来即要动手。“纸上得来终觉浅绝知此事要躬行。” 古人云诚不我欺对于工程师来说尤其如此。 如果是想比较深入的了解一门新的技术甚至有打算切换技术路线和职业赛道那么一定要更多的动手要把这个开源软件用起来或者写一点程序跑个 Demo 并运行在实验环境里面最好解决一些身边的实际问题。千万别眼高手低觉得一切都很简单但是真的要跑起来用起来就千难万难了。可以尝试参加技术企业内的一些创新活动例如 hackthlon黑客松活动把新学的技术用起来或者写一点点小工具让他跑起来解决一点点实际问题。例如如果要练习 Python写一个爬虫每天去爬天气预报网站上的数据然后做一个简单的查询可以获得当前的天气预报情况。在用中学学以致用。
还有一个非常好用的学习方法就是费曼学习法。费曼学习法被认为是最有效、最强大的学习方法之一亲测管用。 步骤也很简单我把它简化为如下三步。
先学习一门技术把它讲给普通人让他听懂如果听众没有听懂回到第一步
通过这种方法只有自己讲解该项技术的用法和架构并能让普通工程师听懂这个技术才算是真的掌握了。
费曼学习法来源于诺贝尔物理奖获得者理查德 · 费曼Richard Feynman。他是一位知名的理论物理学家量子电动力学创始人之一纳米科技之父因其对量子电动物理学的贡献 1965 年获得诺贝尔物理学奖。他所提倡的学习方法被称之为 “费曼学习法”。步骤虽然非常简单但是能把复杂的技术进行简化并让普通工程师能听懂的方式讲出来这需要对这门技术有深入的理解和掌握还需要对一些专有名词和概念进行类比、联想来进行简化。一般能做到这样就说明对这门技术已经达到了入门的程度可以继续进行后续的更深入的学习了。
另外参加业内一些著名课程的考试或者认证也是一种比较好的方式。例如对云原生不熟悉的工程师当他通过 CKACertificated Kubernetes Adminitrator认证 Kubernetes 管理员考试之后这个认证可以验证他具备一定的水平已经建立起对 Kubernetes 常见操作和系统架构比较全面的了解了。
3.3 融入开源社区终身个人口碑
最后一点对于工程师来说参与和融入到开源社区里面积极贡献将会获得终身的口碑并能结交到终身的朋友是十分有利于工程师的长期发展的。 在此鼓励工程师可以选择自己感兴趣的开源项目和社区并通过交流和贡献不断在社区里面成长。即使以后因为工作关系或者其他种种原因不继续在这个开源项目和社区中活跃了但是他的贡献将一直被承认。Apache 开源软件基金会有一句很有名的座右铭“Merit never expires”参见 http://theapacheway.com/merit-never-expires/就是说工程师在 Apache 开源软件基金会项目和社区做贡献获得的认可是永远不会过时的。曾经是提交者永远是提交者。
在开源社区里进行协作也是工程师进行社交的一种方式。在这里能认识终身的朋友能和他们一起工作和交流对于工程师的成长也是非常有效的。很多开源社区的大牛在社区里面也是非常友善的尤其对待新人对待比较 junior 但是贡献欲望比较强烈的工程师更是愿意手把手的教的。在这些大牛工程师的帮助和指引下新人的成长是非常快的而且没有企业 / 部门 / 工作项目等带来的天花板。即新人可以在自己感兴趣的开源项目和社区里面凭借虚心的态度和贡献欲望不断和社区内的资深工程师进行交流和学习可以带来技术能力的飞速发展的。
另外对于现在的工程师来说很难有终身雇佣的企业工程师在企业里面也就是工作一段时间然后随着各种主动或者被动的变化岗位或者就职企业也会发生变化。但是在开源社区贡献所获的认可和建立起来的个人品牌和技术口碑是永远随着个人的不会因为公司或企业的情况而发生变动。能看到很多一直活跃在开源社区的人虽然职业发生了很多变动但是他们在开源社区的认可和品牌一直存在。这也是很多工程师突破职业内卷突破平台限制的一种好办法。
在开源社区长期做贡献是利人利己的好事鼓励每一位有想法有行动的工程师都能找到自己喜欢并投入的开源项目和社区并且融入进去。
3.4 如何在开源社区做贡献
在开源社区尤其是哪些尊重精英治理的社区例如 Apache 基金会的项目做贡献越多得到的认可越多。 但是很多时候作为一个新人要去开源社区做贡献并不是抬抬手就能做的是需要先了解一些社区规则然后遵守规则才能够慢慢融入的。
1. 贡献什么
在做贡献之前我们需要了解对开源社区的贡献并不是仅仅局限于代码贡献写代码增加功能或者 Bugfix 是贡献完善文档和测试用例是贡献报告使用问题是贡献写博客介绍项目和推荐项目也都是贡献这些都是在开源社区内被广泛认可的贡献。
很多社区的技术大牛进入开源社区做贡献是从提交测试报告开始的。比如当年 Mozilla 社区最年轻的架构师 Blake Ross17 岁就成为 Mozilla 社区最高技术决策层之一并和另外一位架构师创立了 Firefox 项目他最初进入 Mozilla 社区是作为实习生从测试开始的。
“Scratch your own itch!” 这是在开源社区流行很广的一句话意思是说在开源社区做贡献是需要解决自己的问题的。即在实际工作中遇到了问题然后尝试去解决最后把解决的结果以社区接受的方式贡献到社区。一般的情况是有个 Bug 或者问题影响用户的实际应用或者想增加一个新的功能来满足企业的自身场景或者就是想学习一些新的技术。这种解决自身需求的贡献是比较长久的。而为了一些蝇头小利参与社区运营的一些活动获取奖励对工程师来说只是 for fun这种贡献也不是长久的。
所以对于一个新人进入到开源社区里面贡献可以从一些简单的问题开始从解决自身的需要开始。 一个最简单的例子先看新手入门文档照着文档描述的步骤一步步走下去看看能否走通如果走不通可以报一个 Bug 出来或者亲身体验需要增加一些额外的步骤才能走通可以给这个新手入门文档提一个 Patch把这些补充步骤描述出来这也是社区很欢迎的贡献。
有些社区把一些简单的 Bug 设定为 “Good First Issue”贡献者可以挑选这些 Issue 来进行贡献来熟悉贡献流程并融入到社区里面。
2. 了解现有社区情况尊重社区的惯例和习惯
给开源社区做贡献的第一步是先了解社区。
可以通过社区的网站、邮件列表、Wiki、github 代码仓库中的文档等资料了解该开源社区的一些基本情况。
通过查看关键文档Contributing.md)了解这些项目的贡献流程和推荐方法。
注意每个开源社区都有自己的惯例比如他们有自己的 Issue 管理系统有的可能用 github 的 Issue有的使用 Bugzilla有的使用 Jira然后提交 Patch 的流程和要求也不一样。
例如历史非常悠久的 Apache HTTP Server 项目它对贡献者的要求如下
Patch 需要符合他们的 Code Style对代码质量也有一些例如线程安全的要求Patch 需要针对当前的开发版本 –2.5.X 来做比较Patch 的格式使用 diff -u file-old.c file.c 来生成提交 Patch 的入口在 bz.apache.org/bugzilla建议加上 “PatchAvailable” 关键字可以在 mail list 中发邮件来讨论邮件的 title 需要为 [PATCH ]
注意他们采用的方式并不是 github 上流行的 Fork/Pull Request 模式而是更古老的 BugzillaDiff Patch 的模式 请尊重他们的工作习惯使用他们要求的模式。说句老实话笔者 20 年前在 Mozilla 社区做贡献的时候工作方式也是采用 Bugzilla Diff Patch 的方式。二十多年过去了Apache 的 HTTP Server 项目的工作模式并没有发生大的变化。不过工作方式不影响贡献熟悉并习惯就好。
有的开源社区会提供一种游戏化的贡献流程即让开发者通过一系列简单的新手任务来熟悉项目和贡献流程。这种方式是对新人更加友好的也是经过该社区的社区经理精心设计的。那么对于贡献者来说别辜负了他们的良苦用心走一遍自己觉得必要的任务熟悉自己希望熟悉的任务和流程就好。
3. 态度需要 “Be Polite and Respectful”尊重社区的多样性
开源社区里面是充满多样性的。
开源社区内大部分的资深工程师对新人非常友好的他们会很有耐心的教导新人熟悉文档熟悉贡献流程等等注意一般只有一次别辜负了。日常交流中包括在邮件列表中在 IRC 或者 Slack 频道中在 Issue comments 中都比较 nice。跟他们的沟通和协作比较容易。
但是注意也有部分人相对态度不是特别好如果遇上了注意不用发生正面冲突。建议可以向社区更资深的一些工程师来求得帮助而不用正面硬刚。不可能改变任何人也不可能让所有人都喜欢完成必要的工作就好。
4. 如何快速找到负责代码 Review 的 Module Owner完成贡献
有的时候按照社区贡献流程的文档走下去不管是提 Issue 或者报 Bugs发现模块负责人反馈很慢的时候这个时候有一些技巧。
可以加入他们的 IRC 或者 Slack 频道找到对应的模块负责人然后跟模块负责人进行礼貌和有建设性的对话。
跟他们建立良好的关系并通过实际的贡献逐步建立起他们的信任。
注意开源社区的运作是以信任为基础的。能获得模块负责人的信任是非常有利于之后的工作开展的。
5. 提交大 Patch 需要注意步骤
可能有的工程师反馈我给某某开源社区提交一个非常好的特性在我的公司内部工作环境内测试并验证效果非常好性能表现非常出色。但是我把代码提交到上游开源社区的时候发现社区并不看重这个特性反而对我的 Patch 指指点点挑出各种毛病。太麻烦了太心累了干脆不贡献了。
需要将心比心的想象一下如果一个陌生人给你的项目提交一个很大的 Patch代码 Review 实施起来就很费劲因为 Patch 比较大。虽然贡献者说这个 Patch 很有用实现了一股很厉害的功能而且经过了他的验证但是他是否可靠他是否能在社区里面长期存在他是否能够及时修复他所提交的代码产生的问题这些都是问号。所以在没有建立起基本的信任之前即提交了几个小 Patch 并得到了和入提交大的 Patch 是很费劲的。
另外提交这个 Patch 的工程师往往并不了解这个开源社区的历史也许这个功能很早就在社区被讨论过了也许讨论的结论是不需要做或者在别的地方来做。所以不要盲目自信于自己的 Patch而是应该先跟社区的工程师先沟通这个场景和问题。
笔者建议贡献的步骤如下
如果判断这个 Patch 比较大那么先在社区内讨论问题让社区认可这个问题同时也能获得社区对这个问题的一些历史信息如果有的话如果社区认可该问题觉得现在应该要修复了继续讨论解决思路问题和思路已经被认可之后并完成一点点设计之后再讨论具体的代码 PatchPatch 需要遵守社区的规范CodeStyle、组件调用规范、测试规范、文档规范等做好心理准备Patch 可能需要反复修改若干次才能最后被和入可能需要把一个大的 Patch 拆成若干个小 Patch分批提交和入。必要的时候需要一定的妥协。
贡献一个大的 Patch实现一个重要的功能步骤虽然多时间周期虽然长但是完成之后能得到社区的高度认可往往是成为更高层级贡献者的基础。而且对于贡献者个人来说内心的满足感和成就感也是非常足的。
6. 注意不要做以下的事情
提出一个 Idea希望别人来完成。
尤其是刚刚加入一个社区的时候就提出社区需要做某些事情但是自己不做希望社区里面的其他人来完成这些意见往往是会被忽略的。“有许多人‘下车伊始’就哇喇哇喇地发议论提意见这也批评那也指责其实这种人十个有十个要失败。” 这种人更是不受社区欢迎的。
提出一个问题同时提供一个有建设性的解决办法而且自己要参加可以邀请社区其他人来一起。这是比较推荐的做法。
2. 过于急切缺乏耐心而忽略了社区的惯例。
宁可速度慢一点尤其是在社区对新人的信任感建立起来之前要有耐心。笔者曾经见过一个刚进入开源社区的工程师技术能力很强但就是只想快点把他的 Patch 和入进去。跟模块负责人的沟通的时候态度虽然礼貌但是对负责人给出的改进意见反应很敷衍。折腾过几次之后该贡献者在该社区的口碑已经被损失殆尽他相关的 Bugfix 和新功能开发进展很慢他后来也黯然离开了该项目。
3. 不要碰红线即社区的行为规范所禁止的一些恶劣行为
基本每个成熟的开源社区都有自己的行为规范Code of Conduct一般都会在该社区网站或者代码仓库的显著位置展示此文件。
规范内容列举出若干社区不欢迎的举动包括性别、种族、宗教等方面的歧视和冒犯。
注意不要有这些行为可能有的行为在中国开源社区里面并不被认为是大问题但是在国际社区不一定是小事。
7. 在企业内部对上游社区做贡献要注意合规问题
在企业内部给上游社区做贡献因为是把公司内部研发的结果公开出去所以需要满足公司内部的开源贡献管理办法。
每个公司对此的规定不太一致。例如谷歌鼓励工程师贡献到开源社区但是要求工程师应该以 google.com 的邮件地址来进行贡献100 行以下的贡献不需要通过内部流程审批但前提是项目没有采用 Google 禁止的许可证例如 AGPLPublic DomainCC-BY-NC-*此外还有一些硬性条件参见 Google OSPO 的官网链接 https://opensource.google/documentation/reference/patching。 国内百度公司也是鼓励工程师贡献到开源社区无论 Patch 大小都需要经过内部的电子流程由该部门的技术总监进行审批并交由百度的开源管理办公室OSPO进行备案以便后续开源办公室的数据统计和对工程师的贡献激励提供数据支持等。
在企业内部给上游社区做贡献的时候往往会碰到该社区要求工程师签署 CLAContribution License Agreement即贡献许可协议或者 DCODeveloper Certificate of Origin开发者原创申明的事情。其中 CLA 又分为 ICLAIndividual Contributor License Agreement和 CCLACoperation Contribution License Agreement即企业级贡献许可协议其中 ICLA 是针对个人的CCLA 是针对整个企业的即如果该企业签署了 CCLA 之后该企业内部的工程师再做贡献就不用单独签署 ICLA 了。不签署 CLA 的话则不能提交 Patch。CLA 条款的内容是贡献者把自己的贡献授权给社区来进行使用。此时请遵守公司内部的规定相关的 CLA 条款可能需要经过公司内部的法务来进行 Review。不过好在一些著名项目的 CLA 条款例如 Apache 开源软件基金会的项目都使用统一的 CLA 文件CNCF 基金会的项目也是类似。这些著名项目的 CLA 条款法务确认之后就没有问题了。如果不是法务已经确认过的 CLA需要跟公司负责的法务进行咨询避免碰上一些对企业不利的 CLA。
总结
本文比较长凝聚本人的很多心得和体会。
一直认为工程师是非常务实非常努力的一帮人是一群深深相信 “我们可以用代码来改变世界” 的人是一群认为 “Talk is cheapShow me the code”、“日拱一卒功不唐捐” 的人。我一直认为 “开放、协作、务实” 是当代工程师最好的特性之一。
在开源世界里学习、工作、分享是工程师改变世界最好的途径之一。