内容简介:【编者的话】由于Jeff Dean的作品深而广,本文特意专注于小而美的Linus Torvalds第二作品:Git,希望从中汲取营养,向大师致敬。文介绍Git核心优点和实现思路,重点引申出对业务系统设计与开发的启示;由于篇幅有限,本文不详细介绍Git命令的具体执行细节,如果需要了解执行Git命令时,底层具体发生了什么,请移步Git作为一个前无古人,很可能后无来者的
【编者的话】由于Jeff Dean的作品深而广,本文特意专注于小而美的Linus Torvalds第二作品:Git,希望从中汲取营养,向大师致敬。
文介绍Git核心优点和实现思路,重点引申出对业务系统设计与开发的启示;由于篇幅有限,本文不详细介绍Git命令的具体执行细节,如果需要了解执行Git命令时,底层具体发生了什么,请移步 Git官方文档第十章 Git Internals 。
为什么关注Git?
Git作为一个前无古人,很可能后无来者的 内容地址跟踪器 ,席卷各大公司,深受所有 程序员 喜爱(觉得Git难用的除外),肯定有他的过人之处。
先搬出互联网技术关键词标配:
分布式、去中心化、可靠性、容错性、可用性、数据一致性、性能是一个功能,而不是一个优化等。
Git都满足有木有!Linus用两周就实现自举的Git十几年后依然健壮如初。假如我写一个接口或设计一个微服务或写一个小工具,自带扩展技能,从来不挂,QPS暴增也无需推翻重构,外部依赖抖动时自动降级,数据量增大而没有拖垮性能,能与Git有很多共同点,岂不很有成就感?
Git最初设计时要达到的目的
分布式:1)多人同一个分支不同地点不同时间并行开发;2)单人本地多分支并行开发。
性能:速度要快。慢是Linus Torvalds本人无法接受的,因为 Linux 内核每天有成百上千次提交。
安全与信任:即可靠性,我push上去的代码pull下来一定还是我的代码,没有丢失或被恶意篡改过。
Git数据建模
插播一条语录:
Bad programmers worry about the code. Good programmers worry about data structures and their relationships.(一般的程序员只关心代码,而优秀的软件工程师更关心数据结构以及他们之间的关系。)
——by Linus Torvarlds.
启示
Linus本人写 C语言 比较多,个人认为这里的data structures and their relationships如果脱离C语言的特定背景,可以泛指技术对场景或业务逻辑的抽象,比如:面向对象建模,领域驱动,甚至更宏观的架构设计或微服务怎样划分。
根据个人经验,如果系统设计的好,代码稍微写low一点,整个系统的表现也不会太差,而且代码的坑比较容易填;反之,再漂亮的代码也很难填上系统设计的坑,只能面临重构。
Git内部文件处理:
- 代码库里所有文件都是数据,以数据为中心,所有操作、存储和处理逻辑围绕数据展开。
- 跟踪整个项目整体状态,每次建立全局快照,而不是跟踪每个文件的变更。
- 针对Git目录下的每个文件计算一个hash值,文件内容作为value,hash值为文件key。
- 如果单个文件内容发生变化,下次重新计算hash值。如果文件没有发生变更,当前快照指向历史hash。
- 整个代码库的变化历史和文件组成用树形结构表示。
- Git每次commit记录整个代码库的一次快照,当前快照包含发生变化的文件和历史快照(子树)。
Git数据建模
Git执行效率与时间复杂度
对于Git内部结构可以简单的理解为:Git内部是一棵 树 ,每个节点都是一个指针(key),这个指针(key)可能代表一个文件,或一次commit或一个分支起点或一次merge或一个tag,key对应的value就是内容,如果key是代表一个文件,value就是文件内容;如果key是代表一次commit,value是一颗子树,包含此次commit对整个项目的snapshot。
平时很多Git操作都可以近似理解为:在树上执行遍历查找O(lg(n)),切换指针O(1),然后根据指针取文件内容O(1))。这些操作速度都是很快的,只有在网络交互,文件压缩与解压和计算diff时,人肉可以感知到有时间等待。
启示
- 数据结构和算法原来是这么用的,基本功还是要扎实呀。
- LeetCode 还是要常刷的。
- 建模很重要。越好的设计模型离被推翻重构的距离越远。 关于架构设计和规划:做技术选型和概要设计,P7级别的就要做到,1年以后当别人接手时就不需要考虑重构,如果是P8的就有信心做到2年以后,而P9的则是3年或更长时间 。Git已经经历了超过10年的考验了。
Git空间压缩与访问效率平衡
对于Git,近期发生变化的数据属于热数据,Git假设这些数据会被频繁访问或使用到。其他数据为历史数据。对于热数据,即使发生微小变化,Git也会全量冗余存储,提高访问效率。当热数据文件数量达到一定值时,会触发打包压缩逻辑,delta差异存储,节省空间。
启示
对于不同的存储介质,例如DB,Redis,MQ,选用不同的存储逻辑或策略,以达到访问效率与存储空间的平衡。
Git安全性与容错性
Git对文件内容和项目整体snapshot都使用hash值表示,hash值与内容一一对应,如果文件内容被篡改或硬盘损坏导致数据丢失,hash值校验都会失败。此时Git设计时已经假设:
- 硬盘是随时崩溃的,即存储是不可靠的
- 有人恶意引入Bug或偷偷修改代码
启示
在分布式环境下,设计系统或接口,能否保持容错性,自带降级,建议多向自己提出假设:
- 网络是不可靠的。接口调用timeout和失败是必然存在的,逻辑应该怎样处理?是否自带降级技能。
- DB是会抖动的,缓存也会失效,主从延迟一定存在的,此时代码逻辑能否兼容?如果fail fast,是否有报警机制?
- 对外的接口,调用方的传参要考虑最坏的场景,是否有合理的入参校验/防重/幂等处理?
Merge算法思想:三路合并
先找出两个分支的公共祖先,然后两个分支分别与公共祖先diff,指出有冲突的地方。Git merge并没有试图智能的去解决冲突,只是指出冲突,然后将merge交给最合适最高效的人去解决:即引起冲突的开发者。
启示
- 选用最合理的数据结构、索引结构或算法思路,不断优化系统处理速度。
- 划清边界,只做自己最擅长和应该做的事情,尽量保证高内聚,低耦合。微服务环境下,在设计系统时,应该多考虑:各个服务调用时,不同的异常谁负责处理;接口超时谁负责补偿;数据一致性交给谁来保证等。
Linus Torvalds眼中好的代码和好的软件工程师
好的软件工程师要有good taste,坚持不懈的追求用正确的方式解决问题。
好的代码,举个例子:移除链表中某个节点。
一般的代码,用if else判断边界值:
void remove_list_entry(entry) { prev = NULL; walk = head; // Walk the list while (walk != entry){ prev = walk; walk = walk->next; } //Remove the entry by updating the //head or the previous entry if(!prev) head = entry->next; else prev->next = entry->next; }
好的代码,换一种写法,使正常处理逻辑可以兼容边界值:
void remove_list_entry(entry) { //The "indirect" pointer points to the // *address* of the thing we'll update indirect = &head; //Walk the list,looking for the thing that //points to the entry we want to remove while ((*indirect) != entry) indirect = &(*indirect)->next; // .. and just remove it *indirect = entry->next }
启示
平时编码中对边界值的处理是否优雅?
现在一个变量的传递会经过多种编程语言和中间件,中间过程一般有序列化和反序列化,给空对象赋默认值等逻辑,怎样保证实际结果与预想的完全一致?边界值处理不好,一是代码不好维护,二是容易引入Bug。日常碰到的边界值有:null,int默认值0等。
其他
- 从用户角度出发设计系统。Linus是Git的第一个也是最粘性的用户,在写Git之前他就已经了解了当时的各个版本控制软件的优缺点,他清楚Git需要实现哪些功能,哪些功能无需实现。
- Git在命令行执行命令时,响应的提示信息及时且准确。
- 站在巨人肩膀上,向已有系统学习。Git最初的核心命令都是复用操作系统已有的功能,例如diff,压缩,文件处理等。
启示
- 自己写的系统或功能,自己要从最终用户角度尝试使用或模拟使用。
- 对于API接口,研发负责自测;写单元测试时,可以从调用方角度思考接口名称和参数设计是否合理,是否抛出异常,返回信息中是否包含错误码和提示信息。
- 既要有造轮子的能力,又要有不重复造轮子的觉悟。
多向开源系统学习,多研究底层原理,大部分原理或设计思路都是相通的。
彩蛋
如下为Linus Torvalds语录,仅供娱乐。Linus Torvalds以喷人闻名,网络上很多人指责他人品不行,很少有人评价他的技术水平,可能是没有能力评价吧。)
- "In fact, I am a very cynical and untrusting person. I think most of you are completely incompetent". In front of a large group of Google developers. 翻译:在一群谷歌软件工程师面前说:各位不要误会,我不是针对你,我是说在座的各位写代码的水平完全都是垃圾。
- "Because nobody actually creates perfect code at first time around except me, but there's only one of me. " 翻译:实际上没人能一次就写出完美的代码,除了我。但是世界上只有一个我。PS:这句话也是在一群谷歌软件工程师面前说的。
链接: https://juejin.im/post/5c381292518825258124e1fc ,作者:饿了么物流技术团队
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
VISUAL FOXPRO程序设计实用教程习题解答与实验指导
康萍 / 中国经济出版社 / 2006-6 / 22.80元
本书为康萍等主编的《VisUal FosxPro程序设计实用教程》的配套习题解答与实验指导教材,由常年工作在计算机教学第一线的教师组织编写。全书共分为三部分:第1部分为实验指导,包括33个实验,分别讲述了每个实验的实验目的.实验内容和操作步骤;第2部分为开发实例,介绍了图书营理系统的分析、设计与实现过程;第3部分为配套教材各章节习题参考答案。 本书实验部分可操作性及实用性较强。系统开发案......一起来看看 《VISUAL FOXPRO程序设计实用教程习题解答与实验指导》 这本书的介绍吧!