如何确保强力恢复数据软件下载公司源代码不会外泄?

如何确保软件公司源代码不会外泄? - 知乎有问题,上知乎。知乎作为中文互联网最大的知识分享平台,以「知识连接一切」为愿景,致力于构建一个人人都可以便捷接入的知识分享网络,让人们便捷地与世界分享知识、经验和见解,发现更大的世界。12被浏览858分享邀请回答赞同 添加评论分享收藏感谢收起Visual Studio - 使用 Visual Studio 对源代码文件进行哈希处理以确保文件完整性
问题和下载内容
第 32 卷,第 3 期
Visual Studio - 使用 Visual Studio 对源代码文件进行哈希处理以确保文件完整性
| 2017 年 3 月
对所有编译的软件语言来说,将人类可读代码转换成计算机可读代码都是一项软件保障挑战: 用户如何有信心相信在其计算机上运行的软件程序是根据开发者创建的同一源代码文件生成的呢? 这不一定,即使源代码文件经过行业专家评审,也不例外,因为可能出现开放源代码软件的情况。软件保障的核心是信任经过评审的源代码文件是生成可执行文件的相同源代码文件。
在编译和链接过程中,使用特定编程语言(C#、C++、Objective C、Java 等)编写的一组源代码文件被转换成二进制可执行文件,以供在特定体系结构(如 x86、x64、ARM)的计算机上运行。但这种转换可能不具有决定性作用。两组不同的源代码文件可能被转换成两组位完全相同的可执行文件。有时,这是有意而为之。源代码文件内空格或文本注释不一致不得影响编译器生成的二进制代码。另一方面,同一组源代码文件也可能会因不同的编译过程而被转换成不同的可执行文件。无论属于上述哪种情况,问题都在于确定性,即无法确定拥有的文件是否就是所需的文件。
为了解决这个问题,不妨在编译过程中使用 Visual Studio 编译器对源代码文件进行哈希处理。将编译器生成的哈希值与经过检查的源代码文件生成的哈希值进行匹配,可以验证可执行代码是否的确是由特定的源代码文件生成而来。这显然会让用户很受益(实际上,如果其他编译器的供应商也采用了类似方法,那么用户会进一步受益)。本文介绍了用于选择哈希算法的新 Visual Studio 开关、此类哈希可能适用的应用场景,以及如何使用 Visual Studio 生成源代码哈希值。
在编译过程中生成强哈希值
程序数据库 (PDB) 文件是一个单独数据文件,存储用于调试二进制可执行文件的信息。Microsoft 最近将其各种编译器文件哈希运算(如 PDB 文件中嵌入的源哈希值)更新为使用强加密算法。
本机代码编译器:Visual Studio 2015 本机 C/C++ 编译器 cl.exe 随附一个新开关 /ZH:{MD5|SHA_256},用于为编译器选择其他哈希算法,从而对源代码文件进行哈希处理。默认开关为 MD5,虽然已知其更容易导致冲突,但仍采用默认开关,因为从计算层面来讲它的哈希值生成成本更低。使用新的开关,编译器可以实现密码强度高于 MD5 的 SHA-256 选项。
如果源代码文件的 SHA-256 哈希值与二进制可执行文件的 PDB 文件中存储的 SHA-256 哈希值一致,就可以确定可执行文件是由相同的源代码文件编译而成,这样所有利益干系人便可以对二进制可执行文件有信心。实际上,二进制可执行文件的 PDB 文件中存储的一组 SHA-256 哈希值全都成为二进制可执行文件的“生成证明”中的标识符,因为这些标识符由“生成”二进制可执行文件的编译器进行注册。
使用调试接口访问 SDK (),可以轻松创建简单的工具,如调试信息转储程序 cvdump.exe(可从
中获取此程序及其源代码)。可以使用 cvdump.exe 的 -sf 开关查看模块(使用本地生成计算机中的完整路径名称)及其 MD5 或 SHA-256 哈希值的列表,如图 1 中的命令窗口所示。
图 1:使用 cvdump.exe 查看模块及其哈希值
使用旧版 cvdump.exe 查看同一 PDB 文件时,我看到的文字是“0x3”,而不是“SHA_256”。“0x3”值是“SHA_256”的枚举值,更新后的 cvdump.exe 知道如何进行解析。它也是调试接口访问 SDK 的 IDiaSourceFile::get_checksumType 方法返回的同一枚举值。
托管代码编译器:默认情况下,Visual Studio 2015 托管代码 C# 编译器 csc.exe 使用 SHA-1 加密算法计算源文件校验和哈希值,以存储在 PDB 文件中。然而,csc.exe 现在支持使用新的可选“/checksumalgorithm”开关来指定 SHA-256 算法。若要切换到 SHA-256 算法,请使用此选项编译当前目录中的所有 C# 文件,然后将调试信息(包括源文件列表和 SHA-256 哈希值)放入 PDB文件中:
csc /checksumalgorithm:SHA256 /debug+ *.cs
中获取属于 .NET 编译器平台 (Roslyn) 开放源代码项目的 csc.exe。有关对文件中 SHA-256 源文件调试校验和算法命令行选择器的支持,请访问 。Visual Studio 2015 csc.exe 只与 Microsoft .NET Framework 4 或更高版本的可执行文件兼容。另一个用于生成低于版本 4 的可执行文件的 Visual Studio 2015 .NET Framework 编译器不支持 /checksumalgorithm 开关。托管代码 PDB 文件存储数据的方式不同于本机代码 PDB 文件。可使用 Microsoft DiaSymReader 互操作接口和实用工具来读取托管代码 PDB 文件,而不是使用调试接口访问 SDK。可从
中以 NuGet 包的形式获取 Microsoft DiaSymReader。
Roslyn 项目包括 pdb2xml.exe 实用工具,可从
中获取此工具及其源。此实用工具以 XML格式显示 PDB 的内容。例如,图 2 中的各段列出了用于编译托管代码可执行文件的 C# 源代码文件。
图 2:以 XML 格式显示托管代码 PDBcheckSumAlgorithmId 字段中的“b8-0e8597ac16”GUID 表明,校验和字段中的值是名称字段中引用的文件的 SHA-256 哈希值。可移植 PDB 格式规范 v0.1 () 中定义了此 GUID。
编译器对 SHA-256 的支持以下 Visual Studio 2015 编译器支持对源代码文件进行 SHA-256 哈希处理:
cl.exe /ZH:SHA_256ml.exe /ZH:SHA_256ml64.exe /ZH:SHA_256armasm.exe -gh:SHA_256armasm64.exe -gh:SHA_256csc.exe /checksumalgorithm:SHA256可在 Visual Studio 2015 的“VS2015 开发者命令提示符”命令窗口中创建这些编译器。不面向 Windows 平台的编译器通常不使用 PDB 文件存储其调试信息。这些编译器通常在编译期间同时生成两个可执行文件,一个是未删除源信息的可执行文件,另一个是已删除源信息的可执行文件 ()。所有调试信息都存储在未删除源信息的可执行文件中,而已删除源信息的可执行文件则不包含任何详细的调试信息。未删除源信息的可执行文件可能适合存储可执行文件的已处理源代码文件的 SHA-256 哈希值。我们正打算联系其他这些编译器的创建者,确定最适合其编译器的方法,以便使用这些编译器的非 Windows 软件(如 Office for Android、Office for iOS 或 Office for Mac)可以和 Windows 软件一样受益。用例应用场景
现在,我们来看一下源文件哈希值可能适用的一些应用场景。
检索可移植可执行 (PE) 二进制文件的已编入索引源文件:Ssindex.cmd 脚本 () 是一种实用工具,可用于生成签入源控件的(已编入索引)源文件列表,以及每个文件的版本信息,以供存储在 PDB 文件中。如果 PDB 文件包含此版本控制信息,可以结合使用 srctool 实用工具 () 及其 -h 选项来显示信息。由于已编入索引的源文件也将其哈希值嵌入 PDB 文件,因此这些哈希值可用于在检索期间验证源文件,如知识库文章 3195907 ()“How To Retrieve Indexed Source Files of a Portable Executable Binary File”(如何检索可移植可执行二进制文件的已编入索引源文件)中所述。 具体来说,如果哈希值不一致,则表明 PE/PDB 对生成期间或源控件系统中的某个环节可能出现了问题。这可能有必要执行进一步调查。相比之下,如果哈希值一致,则充分表明检索到的已编入索引源文件是用于编译 PE/PDB 对。
匹配源文件静态分析器生成的哈希值:现在,使用自动工具来评估软件质量是常事,就像 Microsoft 安全开发生命周期 (SDL) 针对实现阶段建议的一样 ()。具体来说,源文件静态分析器用于扫描目标源代码文件,以评估软件质量的许多不同方面。这些静态分析器通常在扫描目标源代码文件后立即生成相应的实时结果。在静态分析器扫描各个源代码文件时,也是生成每个在扫描源代码文件的强哈希值 (SHA-256) 的绝佳机会。实际上, 中开放源代码项目提出了静态分析结果交换格式 (SARIF),这种格式提供了静态分析结果中的特定位置,以供静态分析器生成扫描的目标源代码文件及其 SHA-256 哈希值。 以 PE 文件为例,假设可获得以下内容:由编译器生成的相应 PDB 文件中的编译源文件哈希列表。由静态分析器生成的相应静态分析结果中的扫描源文件哈希列表。在此应用场景中,可以评审并验证这两个文件哈希列表是否匹配。如果匹配,表明静态分析器已扫描源文件来评估某方面的质量,无需重新扫描源文件。以前没有文件哈希列表,可能就需要重新扫描,以确保静态分析器进行了正确的评估。
在软件更新或修补程序开发过程中更快速地执行健全性检查:如果需要发布软件更新来修复源文件静态分析器在已发布产品中发现的质量问题,静态分析器应报告待定更新程序的源代码文件中不存在发现的质量问题。这个报告至少将确认更新程序能否有效解决原始质量问题。也就是说,它将验证软件更新的预期用途。如果需要,你或安全评审员可以执行下列步骤来实施快速验证: 确认原始静态分析器报告是否发现相关质量问题。确认原始静态分析器报告是否包括存在质量问题的源文件的哈希值。将原始静态分析器报告中发现的文件哈希值与已发布产品版本的源文件的哈希值进行匹配。使用同一静态分析器扫描更新程序的源代码文件,生成更新后的静态分析器报告。确认更新程序的静态分析器报告中是否不存在之前发现的质量问题。将更新后的静态分析器报告中的文件哈希值与更新程序的源文件的哈希值进行匹配。在执行这些验证步骤期间,无需访问原始发布产品或更新程序的实际源代码文件。 构造两个软件版本之间的源代码增量:评审一组完整的源代码可能需要一些时间。然而,在某些情况下,不一定非要在更改源代码后评审全部源代码。因此,可能要求只评审源代码增量。这样的要求当然合理,因为重复分析上次评审后没有变化的所有部分并不合理。
以前没有源代码文件的密码强度高的哈希值,很难精确构造增量子集。即使你有增量子集可以提供,行业专家也可能对你能否准确创建增量子集没有什么信心。但现在情况已不再如此。借助源代码文件的密码强度高的哈希值,可以执行下列步骤来创建增量子集:获取原始产品版本的所有源代码文件的哈希值池(例如:池 X)。精确复制文件目录(例如:目录 A),其中包含后续产品版本的源代码登记,将根据其构造增量子集。准备用于仅保留增量文件子集的最终文件目标文件夹(例如:目录 B)。整理目录 A 中的所有文件:
a.如果文件的哈希值与池 X 中的哈希值一致,什么也不做,匹配下一个文件。
b.如果文件的哈希值与池 X 中的哈希值不一致,将文件复制到目录 B 中,然后匹配下一个文件。确认目录 B 中所有文件的哈希值与后续产品版本的源文件的相应哈希值一致。
让目录 B 的内容成为后续产品版本的增量源文件子集。
生成哈希值现在,我们来了解一下如何使用 Visual Studio 编译器对文件进行哈希处理。为此,我将以联机 Visual Studio 文档 () 中的“Hello, World”应用程序创建应用场景为例:介绍在输出 PDB 文件中在何处可以找到编译的源文件的哈希值使用 certutil 工具 () 计算源文件哈希值,与 PDB 文件中的哈希值进行匹配。
首先,我在 Visual Studio 2015\Projects 文件夹中新建了一个 Win32HelloWorld 应用程序项目。在这个 Win32HelloWorld 项目中,只有一个 C++ 源文件 Win32HelloWorld.cpp,如图 3 所示。图 3:Win32HelloWorld.cpp如你所见,Win32HelloWorld.cpp 包含用于显示“Hello”文字的主函数。生成 Win32HelloWorld 项目后,我在 Visual Studio 2015\Projects\W32HelloWorld\x64\Debug 文件夹中生成了 W32HelloWorld.exe 和 W32HelloWorld.pdb 文件。对 W32Hello-World.pdb 文件结合使用 cvdump 工具和 -sf 选项在输出中显示 Win32HelloWorld.cpp 文件及其 MD5 哈希值,如图 4 所示。图 4:显示 Win32HelloWorld.cpp 及其 MD5 哈希值的 cvdump 输出此哈希值是 MD5,因为 MD5 是 Visual Studio 2015 编译器 cl.exe 的默认算法。若要将源文件哈希算法切换成 SHA-256,我需要向 cl.exe 提供 /ZH:SHA_256 选项。为此,我可以在 Win32HelloWorld 项目“属性”页上的“其他选项”框中添加“/ZH:SHA_256”,如图 5 所示。图 5:将源文件哈希算法切换成 SHA-256在 Visual Studio 中重建后,我在 Visual Studio 2015\Projects\W32HelloWorld\x64\Debug 文件夹中生成了 W32HelloWorld.exe 和 W32HelloWorld.pdb 的新 PE/PDB 对。现在,对新的 W32HelloWorld.pdb 文件结合使用 cvdump 工具和 -sf 选项在输出中显示 Win32HelloWorld.cpp 文件及其 SHA-256 哈希值,如图 6 所示。图 6:显示 Win32HelloWorld.cpp 及其 SHA-256 哈希值的 cvdump 输出现在,我可以返回到 Visual Studio 2015\Projects\W32HelloWorld\W32HelloWorld 文件夹中的 W32HelloWorld.cpp 文件,查看它的 SHA-256 哈希值。对于 SHA-256,对 Win32HelloWorld.cpp 文件结合使用 certutil 工具和 -hashfile 谓词生成 SHA-256 哈希值,如图 7 所示。图 7:使用 Certutil 生成 SHA-256 哈希值很显然,此哈希值与 W32Hello-World.pdb 文件中记录的 SHA-256 值一致。这充分表明 W32HelloWorld.exe 应用程序确实是按预期由 Win32HelloWorld.cpp 文件编译而成。若要详细了解适用于本机代码和托管代码 PE/PDB 文件对的相关公共工具,请参阅知识库文章 3195907 ()“How To Retrieve Indexed Source Files of a Portable Executable Binary File”(如何检索可移植可执行二进制文件的已编入索引源文件)。总结我希望通过本文你可以了解到,更紧密地关联源代码文件和用其编译的 PE 文件可能会带来的一些好处。可以在编译过程中使用最强的可用哈希算法 SHA-256 让编译器对源代码文件进行哈希处理,从而更紧密地关联两者。实际上,编译器生成的源代码文件的实际哈希值成为了用于编译可执行文件的源代码文件的唯一标识符。了解这些唯一标识符的值后,就可以在不同软件开发生命周期计划中使用它们跟踪、处理和控制与特定可执行文件有着紧密联系的源代码文件,从而让最终用户对可执行文件更有信心。
Mike Lai 刚刚迎来他在 Microsoft 工作的第 20 个年头。他很感谢 Microsoft 能够提供各种机会来推动许多产品在功能及工程方面取得进步。他想要感谢可信任计算部门现任管理层能够耐心等待他的思想变成熟并逐步融入已发布的产品,另外还要感谢他们支持加入信息和通信技术安全标准组织。
衷心感谢以下 Microsoft 技术专家对本文的审阅: Scott Field、Mike Grimm、Sue Hotelling、Ariel Netz、Richard Ward 和 Roy Williams
Current Issue
Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.
您对此内容的反馈非常重要。请告诉我们您的想法。
更多反馈?
1500 个剩余字符
我们非常感谢您的反馈。软件公司要如何保障源代码的安全不会被外泄,不会被员工泄漏?_百度知道
软件公司要如何保障源代码的安全不会被外泄,不会被员工泄漏?
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
先回答你的问题,然后扩展开说说我的看法。
有些公司是这样做的:为工作场所划分保护级别。
为每台服务器和计算机定义保护级别,并制定相应保护级别下的保护策略,包括授权和访问方法。
将场所分为工作区和上网区,工作区不连外网,上网区是员工共享的非专用机。
封闭所有计算机的外部接口,比如USB口、光驱没有刻录功能、disable蓝牙,不允许计算机和U盘或手机等外设交换数据。
所有对外发的数据统一由高层来接口审核。所有计算机安装后台监控软件,监控操作行为。
普通员工不配置笔记本电脑。
办公空间安装摄像头监视异常行为。 和员工签署保密协议。等等上面的措施的确能起到一定保护作用,但是不能保证绝对不发生问题:公司开展业务必然要和外部进行信息交流,即使在硬件上做到了上述这些,如果真有居心不良的员工,那么只是增加了作案的难度,只要能上网,想把信息传到外部还是有办法的,比如把想窃取的信息通过编码的方式打包到正常外发的文件里。
可以在摄像头死角的地方,暴力破坏计算机,或者把计算机硬盘拆下来拿回去研究。
最不济还可以把核心代码写到笔记上,你总不能不让员工写读书笔记吧。
互联网公司产品的很多代码都是基于开源框架演化来的,有些开源许可是基于GPL的,是要求其衍生物是免费开放源代码的。虽然有很多公司会取巧地绕开这个限定条件。
对于游戏公司,设计、策划、代码的保护是蛮重要的,因为开发期的游戏设计一旦外漏,很可能就失去了市场先机。
照我看,除了专用算法、特定的格式保护、极少数产品本身固有的设计、某些特殊行业(比如网游)之外,很多代码都是通用的,可开放的。有以下一些建议:清晰自己所在的行业特点,对代码外泄做个风险评估,确定保护代码安全的思路和策略;
划分核心代码和非核心代码,分别制定保护策略;
在核心代码上下功夫,能接触这些代码的人一定是可以信任的人,尽可能地少,但也要考虑备份人选;
把核心代码做成编译好的库供程序调用,这样就能降低核心代码泄漏的风险;
员工入职签署保密协议;
选拔高层注重品德和忠诚度,签订竞业保护协议;
最后公司领导要有一个开放心态,正因为有开源的出现,才促进了计算机软件的发展,固守着自己的一亩三分地,早晚要被对手超越。想在竞争中脱颖而出,首先要去除管理者的保守心态。开放、公平竞争才让公司更有底气和信心。
采纳率:54%
为您推荐:
其他类似问题
源代码的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。如何确保软件公司源代码不会外泄? - 知乎有问题,上知乎。知乎作为中文互联网最大的知识分享平台,以「知识连接一切」为愿景,致力于构建一个人人都可以便捷接入的知识分享网络,让人们便捷地与世界分享知识、经验和见解,发现更大的世界。12被浏览858分享邀请回答赞同 添加评论分享收藏感谢收起您的位置: >>
  好的程序员从来不靠格子衫或者颜值吃饭,就像你家 C 罗明明可以靠脸,却非要用不断精进的身体和技术迷倒你。
  对伟大前锋来说,进球,以及一个能够迸发出进球能力的身体非常重要。
  对靠谱程序员来说,代码质量,以及一颗能够洞悉高质量软件编写之道的大脑弥足珍贵。
  本文从产品,接口,指标,日志,代码清晰度,代码复杂度等方面,谈谈如何提高代码质量。
  产品和接口
  好的产品经理未必是个好的程序员,但好的程序员一定是个好的产品经理。
  产品经理的工作是什么?是把复杂的逻辑用清晰的,易用的方式(接口)展现给用户。
  程序员的产品是代码,代码的用户是其他程序员 && 所以高质量的代码是让别的程序员容易理解,容易使用的代码。注意,这个层次的容易理解,是指结构,原理和接口上容易理解,而并非代码的细节容易理解。
  细节在产品这个层次,一定要隐藏起来。用户在打开浏览器,访问&http://arcblock.io&的时候,并不需要关心 DNS 是怎么工作的,PKI 体系是怎么运作的,HTTP / TLS / TCP / IP 协议是什么,报文是怎么从 user space 交付到 kernel space,再怎么 DMA 到网口发送出去 && 这还没完,接下来出场的,还有负责 L2 protocol 的 switch,保护你安全的 firewall,邮递员 router,以及明明概念上是网络技术,却整个青春都错付给了安全的 NAT。。。
  如果产品经理做的产品展示给用户是这样巴拉巴拉的细节,那么丫一定会被扯烂暂住证,大耳光从天黑抽到天亮,然后早班绿皮车送到清河去挖沙;如果程序员的&main()&如此啰嗦,不管人家受得了受不了,那么他这辈子笃定找不到同性朋友,更别说异性了。
  所以程序员在写代码之前,先要想想如果这是一篇演讲稿,我该如何说起?我能在三五分钟讲清楚这代码要干什么?有没有生活中或者同行会心一笑立刻 get 到的例子可以类比?
  90% 以上的情况,程序员是在写 parser。换句话说,我们写的绝大部分代码就是把一系列的输入,经过若干转换(transformation),变成一系列输出。
  举些具体的例子。
  前端工程师是把用户的 url 请求,parse 成浏览器 DOM 上的一系列 component,把用户的行为,parse 成某种内部的事件&{event_type, event_data},并且进一步由&event_typeparse 成某个&event_handler&&& 然后这个 handler 继续 parse&event_data,直到其转化成新的 DOM,或者对后端的某个 API 的某个请求。
  对于 API 来说,它 parse request,生成 response。request 可能被 parse 成一个 sql,交付给 database;也可能被 parse 成满足另一个服务接口的 request(比如 grpc),交给另一个服务。这样周而复始,直到 API 收集完七颗龙珠召唤神龙各个服务的所有数据,再 parse 成一个合规的 response,交还给 client。
  所以程序员看待自己的代码产品,要像庖丁看待肥牛一样 &&「未见全牛」,「神遇而不以目视」,「以无厚入有间」&& 满眼望去,就是一个个 parser,大的 parser 挂小的 parser,再挂更小的 parser。每层,甚至每个 parser,都是个 pipeline && 它们一般由 validator,serializer,transformer 等接口组织起来,辅以各种 builder,decorator,factory,commander,再加上为之而生的 tools,utility,helper 等搭建而成。
  这样一层层组织下来,该粗的地方粗,该细的地方细,遇人说人话,遇猿说猿语,代码可伶可俐,可萝可御。
  接下来,是很重要却最让人挠头的事情,给你的大大小小的模块取名。名字倾注着感情,就像寒夜里小女孩划下的火柴,酣战一宿的圣盔谷外甘道夫挥起的魔杖,给人以光明,温暖,希望,以及读到时触电般的「我懂你」。
  肖申克的救赎里有段,午餐时 Andy 问大伙那个前夜里被打死的可怜的胖子叫什么?大伙一脸懵逼,说我 TM 为什么要关心一个死胖子的名字。这一幕看着很痛,就像华安在成为华安之前,只有一个如蝼蚁般微渺的代号。如果你想让你的代码不是一个让人漠视的死胖子,而是人们愿意谈论,那么,取个容易让人理解,甚至让人刻骨铭心的名字吧。
  不好的名字除了让人不解,漠视,甚至宛如与人世间幽隔的恶鬼,望上一眼,大家便想逃离;好的名字,嗯,随便说一个,聂小倩,同样是与人世间幽隔的孤鬼,你我却念念不忘。
  在 Juniper,我最忘不了的两台服务器是 gretel 和 hansel,取自格林童话;在途客圈,让我心心念之的项目是 atlantis 和以及其上 viking (code name) && 这不难理解,要追寻 atlantis,你需要远征 (viking);在 tubi,cms service 是个糟糕的取名,merlin 算是回归了正途,虽然作为一个 build service,它的魔力并不太强,还时不时失灵;而在 arcblock,我在上篇文章里谈到的 AADL,被正式取名 AODL && 这不重要,估计你也记不住,不过,她有了一个对外的名字:goldorin && 托尔金为中土大陆精灵族发明的精灵语。
  在《》那篇文章里,我提到晦涩的 IKE 代码里 pitcher / catcher 让协议的 negotiation 读来犹如欣赏棒球比赛。好的名字,和好的接口几乎成对出现,它让程序员的产品 && 代码,变得鲜活,读来如沐春风,如饮醇酒,如赏佳人。
  指标和日志
  好的产品是在改进中不断提升的,就像凤凰,经历烈火不断煎熬,得以涅槃。而要想改进,离不来测量 (measure),它是构建 (build) 和学习改进 (learn) 中间最重要的一环。
  热力学第二定律是最让人讨厌也最让人无奈的定律。它直接导致了「不运动肚子上的赘肉必然增加」,「不收拾房子房子会越来越乱」,「不持续改进代码,代码的质量会越来越低」这些让人烦心的事情。
  而这个破定律的祖师爷 Lord Kelvin 说:
  嗯,测量很重要,非常重要。如果构建和改进是两根枝杈,测量就像蜘蛛在两者间挂下的网,这网越密,两根树枝间的路就越多,就越容易从一端走到另一端,循环往复。
  对于测量的途径主要是指标 - metrics 和日志 - logs。metrics 像是心电图或者 CT,让身体的状况一览无余。所以 metrics 用来了解现状,指明方向;logs 则是细密的日记,什么都有,唯独没重点,所以常常在现状和问题的方向确定后,用来归因。比如说 CT 报告说,这周和上周相比,肝不那么好了,需要小心肝。那么肝为什么不好?把一周的日志调出来一看,哎呀,夜夜酒吧里纵情于世界杯,难怪。于是得出改进方案:世界杯结束后,别又喝酒又熬夜又赌球这病就好了,没事。
  metrics 和 logs 大部分时候是给自己和别的程序员看的,所以从上文的角度看,它也是个产品,符合产品和接口定义的一切准则。
  先说 metrics。
  定义 metrics 的时候,你要先搞明白你要改进些什么,这是所谓的 begin with the end in mind。代码的运行效率?那么,究竟那里效率不高?怎么定义效率,怎么计算效率(latency? throughput? 还是什么)。代码的容错性?那么,什么样的 error 要收集,如何分门别类?哪里是潜在的错误大本营?
  知道要改进什么后,接下来脑袋里要有幅图 && 不是富春山居图 && 是自己或者别人使用这些 metrics 的场景预现图,就像至尊宝给山贼展示他和白晶晶的旷古奇恋的画面一样。
  比如说要提高效率,并且确定是降低 latency,所以打算收集服务的 response time,那么,response time 是看 line chart 还是 bar chart,知道了 latency 突然升高这件事之后,下一步呢?怎么知道再看什么?要和其它 metrics / event 关联么?关联哪些,怎么关联?想想意外事件发生之后,作为唯一可以背锅的程序员,身后一堆产品运营盯着你的屏幕,丧着个个脸,表情比出殡还悲壮,好像你一秒钟给公司损失几十万上下似的。在紧张的汗水打湿了你的格子衫时,你能看些什么,你该看些什么?
  这样从解决什么问题,收集什么 metrics,怎么关联使用 metrics,一层层定义下来之后,我们可以确保两件事情:1. 当坏事发生的时候,我第一个知道。比如:对外的 API 的 95 percentile 的 response time 过去 5 分钟突然增加了 30%。2. 我能快速锁定问题的大致范围。比如:从其它 metrics 上看,是因为 diagon alley 服务的 latency 突然升高,进一步地,diagon alley 的 disk write IOPS 显著提高。那么这个问题,我就看为什么 diagon alley 的 disk write 不正常。
  接下来是 logs。
  logs 是不出问题不必太在意,但一旦出问题一定要能够方便定位具体的位置的奇葩重要数据。所以 logs 求充足具体,要像辞海一样广而全 && 比如当 metrics 告诉我们,问题出在我们并不清楚茴香豆的「茴」字时有几种写法,logs 能够帮助我们快速翻出来有用的那段,然后找出「茴」的四种写法。
  logs 兼具给人看,和给机器分析两种效用,因而,最好要固定格式,以方便机器分析;但又不要用类似 JSON 的供机器阅读的方式,如果不配合一个好用的 parser,当人阅读时像是韩式整容过的足球宝贝,或者被抽干了形容词的句子,每个都长得一个模样,需要摘了眼镜用放大镜仔细找不同。
  通过合理的 metrics 和 logs,测量变得唾手可得。这便释放出来我们不断迭代不断改进的能力。同样起点的代码,同样水准的程序员,一个一周迭代一次,一个一天迭代一次,其累进的质量在若干周期之后,会有质的变化。
  代码清晰度和代码复杂度
  如果上面几个方面都做好了,代码的质量再差也是有下限的。这个下限可以通过严格使用 linter 和不断提升对所用语言的掌握来提高。就好比一个会独立思考并勤于思考的人,他的文章值得一读,也许从遣词造句,从修辞手法,从原起承提来说,他还稚嫩,但那是下限,并且是很容易提升的下限。
  在 elixir 的 linter 里,我把 ABC complexity size 设置为 70,Cyclomatic complexity 设置为 15。所谓 ABC complexity,是代码里的 assignments(A),branches(B),conditionals(C) 的平方之和开方根的结果,它代表了一段代码有多冗长。Cyclomatic complexity,或者说循环复杂度,是指由程序的源代码中量测线性独立路径的个数,它代表了一段代码有多难懂(我们的小脑仁最不擅长同时记几件事情,比如情人节和结婚纪念日)。还有一些其他的设置,比如 nesting(嵌套层数)不超过 3, arity(函数的秩,或者说参数个数)不超过 6 个等等。这些 lint 的约束,会强迫你在函数的实现细节层面,考虑地更好。大部分情况下,同一个功能的代码可以有不同的表述方式,linter 的目的就是建立约束,强迫你用更合理的方式去表达一个功能点。
  比如我常常不经意写出的代码:
  这样降低了代码的 complexity,提高了代码的 clarity,同时,还使得代码的 extensibility 大大提升 && 以后要加一个 &type 3& 的处理,仅仅是加一个简单的函数而已,非常符合 open/close 原则。
  这样的小技巧有赖于对语言的精进,和对 linter 规则的恪守。虽然例外偶有发生 && 比如一个复杂的 sql query 用 Ecto 表述很容易超过 ABC,但绝大多数情况,守着规则,会让你受益 && 每次 commit,过 linter 就像灵魂在桑拿房里给蒸气熏碾,痛苦难耐。勉力熬过去后,推门出去一下子无比清爽,有种拨云见日,level up 的感觉。
  禅定时刻
为革命保护视力,预防近视,眼保健操,开始!
  眼睛是心灵的窗户,更是程序员除了左手和右手之外,攻城略地,气吞山河的利刃。最近重温了曾经折磨陪伴自己十二年的眼保健操曲子,豁然发现,原来我们保护视力,是为了革命啊!你看,还好我小时候认真做眼保健操,否则要错过多少革命:通讯革命,互联网革命,移动互联网革命,云计算革命,大数据革命,庵の,区块链革命。
  &此处我欠你们一个眼镜厂商,眼药水厂商,以及去眼角纹,拉双眼皮的广告&
程序人生热门文章
程序人生最新文章}

我要回帖

更多关于 360数据恢复软件免费版 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信