人生得一良友不易,友人是做数据库DBA(运维方向)出生,对软件开发算是没有什么经验,但是最近手头却有点儿事让它对软件这件事开始有了兴趣。于是就问我这个问题。我呢,水平很差,这么大的标题丢过来,怎么回答呢?好在友人给明确了方向:
代码管理,版本控制,补丁管理,架构设计,模块划分,接口设计,报错编码制定,日志设计,测试方法,安全管控,性能规划
1、代码管理,版本控制,补丁管理
对于单一产品的公司,其实问题就是各种迭代和这些迭代的管理。
首先是坐下来讨论一下影响我们代码变化的因素是什么?需求、bug,计划内、计划外?
传统的软件管理,通常会把需求分成很多期,然后针对每一期制定版本计划,然后按着计划做。
但是现代软件偏向于敏捷的管理方式,用用户故事将需求分解成不同的场景,进行故事管理,然后通过迭代的方式向前,然后及时修正项目的整体目标。
回到代码管理,我有个原则,就是你不管是需求还是用户故事,在你打开你的电脑开始写的时候,就要明确你在为什么功能而coding,然后你每一次提交版本必须和你的代码库,task(一种集成在项目管理工具里面的任务,你也可以理解为excel里面的一行需求)一一对应。比如你今天就是做了一个接口,接口只完成一个功能,比如修改密码。那就写清楚你在做什么,然后和你的需求哪些相关。简单地说,就是每一次提交是一个原子提交。然后提交的时候,至少需要保证你的代码是可以编译通过的。
版本控制呢,通常需要考虑到分支的管理和标签的管理。其实我有一个保证它安全的好办法,那就是不用版本控制工具。它们不如复制粘贴/压缩包来的可靠。如果你确定一个分支要发布,首先你需要用版本工具进行分支发布,然后针对分支的补丁就在上面继续,然后适时往主分支合并。但是于此同时,请做一件事,将它们下载下来,把它压缩起来,然后放到一个文件服务器上。然后一旦出现问题,找个文本比较工具,你通常就豁然开朗了。
补丁管理这件事,刚刚也提到过了,你真对哪个版本出的问题,就在哪个分支上面去改,然后适时合并,适时当然是你在差异没那么大的时候做是最好的。
这里插一句题外话,敏捷的核心我个人认为不是在怎么说清楚用户故事,而是你要有单元测试,没有这个都是扯淡……当然其它也很重要,但是UnitTest是必要级别的。这也就是外包软件行业通常做不到敏捷的一个重要原因,因为不是那么容易做到。
2、架构设计
架构设计这可不是那么牛逼的一两句能说明白的事情,不过有几个个人认为还是比较重要的原则。
a、适度设计,其实拿捏这个度,何其难,在一个人开始看待一个问题的时候,自然就有自己的观点在里面,你的视角一定不是世界的中心,那么合理拆分就可以了,本着实用主义的精神做架构设计,通常能在成本、智力等方面都能取得一个还不错的平衡。
b、合理,其实面向对象编程最牛逼的地方就是让一段代码试图去模拟一件事的本身,这就像数据库设计里面的关系表一样,它一定要表达的是正确的关系,那么哪怕它性能上有缺陷。这些其实和什么代码可读性等都是相通的。这就是为什么大部分人都认为多线程程序会比较难,因为它通常不是人类思维。这样的合理设计通常从数据库的设计上面就开始影响你整个复杂度了。这一条通常随着架构师见识和对问题的理解程度不同,在项目进展的不同时期会有不同的体会,一开始合理的东西,在项目后期可能就不是那么回事了。
上面说的都是废话,因为不具备操作性,就是在你要做决定的时候去回想一下才有帮助。那么有什么规律可循呢?
其实通常我们都是习惯带着问题去解决它们的,比如你的性能要求很高,你要求达到一个特定的SLA,那么你在开始选择技术和框架的时候就要在这些方面都比较小心,然后用你熟悉而不是你似懂非懂的技术来解决,这样就算出问题,你至少能知道怎么去思考这个问题,而不会去怀疑那个东西不靠谱。然后就是包括所有影响这些的点,既然说的是性能问题,那么数据库、索引等都是需要考虑的,还有一些可以从业务上分开的,也可以从业务上解决,比如明明一个页面用户只想看到一个数值,但是你总是在页面上带一个大列表,而大列表刚好又查询了一个大表,那么这个页面必定有问题。
3、模块划分
模块划分其实就是你把你的功能合理分拆的过程,你能把你们家的主卧、次卧、厨房卫生间拆分开,你能搞清楚为什么电商分类里面不会把电风扇放到数码产品里面,就说明你掌握了模块划分的基本规则。这些都是纵向划分,按照领域进行细分。
我觉得你这里是不是想要知道的还包括分层管理,软件是个上下叠加的层次结构,其实从你下面跑的硬件到操作系统这一层级通常被做好了,然后就是做好你的软件的部分,所以接触你的操作系统的通常是软件公司给的各种框架,比如.net framework和java虚拟机等,然后就是那些架构框架,什么asp.net、servlet等,这些都不涉及到你的业务,通常是解决了技术层面的问题,然后你现在看到的成熟的解决方案通常都从界面开始(也许是个接口,总归和外界有个交互),然后从这一层中向下,到刚刚那层底层框架之间就需要你自己来分了。看看你是不是需要访问数据了,比如数据库,不管是sql还是nosql,总归需要去联一下了,这里多是考核你层间接口的设计能力,然后你想象你设计的接口就像插座上面的标准插口一样,上层不再关心下层的实现细节,如果下层有问题,让下层去改好了。然后一层一层往上剥离,就到了你刚刚想要做的对外的那个界面了(也许是接口)。什么三层架构什么的,也只是对这些的一个大致归类。
不过按你的思路,也许你的脑子里是个VisualStudio里面的Solution的Panel,你想知道的是一个大的解决方案中各种程序集(dll/lib)的分类方式,那么你回到你最熟悉的Windows/linux下面好了,负责网络的就是网络驱动,管它怎么实现的,我反正负责网络的,你找我就可以了。然后负责IO的,就负责IO就好了。程序集的划分差不多也就是这样的,以SSO举例,加解密我们会有单独的模块,然后做具体业务逻辑的也会有,然后一些辅助的小代码(比如查一下ip地址啊什么的),大概也就是这样一点点分出去。
4、接口设计
上面的很多思路其实在接口设计中都是相通的,其实就是职责分明,一个接口尽量完成一个原子操作,不要完成很多件事,除非你把它当作一件事来做。这个粒度的把握也需要思考清楚。比如修改密码的接口,你就不要再加入重置密码的逻辑,哪怕你背后的代码恨不得调用同一套,也需要暴露两个接口。接口之所以被设计出来,就说明它是相对稳定的,任何对接口的修改,都是一次玩命,原则,约定的功能是不可以减少的,哪怕是不合理的,这个才是接口最难的地方。就像你发布了电灯底座接口,然后全世界都在为你生产电灯,然后你说不行,圆的你不喜欢你喜欢方的,我改了哈,然后,你懂得,上街不要被人打。那么接口的设计就非常需要合理,哪怕你留下一个没有用的参数,内部你压根不用,你写死都可以,但是一定要合理,只有这样,未来使用这套接口的标准程序才不会受到影响。然后单元测试的思想就很重要了,接口永远要保证之前测试的场景在每次升级后还能正常被跑过,否则你的接口随时有可能产生涟漪反应。
5、报错编码制定,日志设计
万物归本,这件事就是你确定一个列表,然后把它吐出来的过程,Windows那么多弹错,无非也是一堆编码,出了问题到kb里面一搜就出来各种编码了。至于这个规则是按类似手机号或邮编的编码方式还是按照条形码的方案来,这个仁者见仁场景也不一样,哪怕你毫无规律地来编,它们都只是起到了一个Id的作用。
这里可能需要提到的一点,这个编码和日志设计通常都在一起,其实在你程序需要记录的时候,哪怕你觉得它八百年才会发生一次,你也要需要给人一个合法的编码和完美的解释,那么你就不至于当系统弹出“有错”的时候,你一看有十几处一样的错误。我倾向于错误始终唯一的方式。
在现代软件编程中,可以借助AOP的思路来将它们收集起来,这个思路和程序横向切片差不多,它在代码上的体现通常是,你的代码明明只是做了业务逻辑,但是它自动会帮忙记录日志,而且能告诉你到底是哪个程序第几行在什么地方干了什么。当然这个也是有代价的,就像你在水龙头上安装了过滤器,那么水流自然要小一点。
现在有nosql了,海量存储变的更方便了,然后分析这件事借助离线计算的方式,总归是能算出来的,但是记得,一定要把信息尽可能多地记录下来。
6、测试方法
传统的测试当然非常重要,什么冒烟测试、用户验收测试、回归测试、集成测试等都非常重要。
这里要提到的更多的是自动化测试,虽然我在项目中很难用到这一点,但是它的思想我非常认同,因为它是用代码来测试代码,代码是什么,是你经验的积累,你找个妹子上去点一遍,点的过程就是经验,你让妹子点20遍也许妹子能朝你踹一脚,但是代码一旦完成,只会越来越趋近精确。现在软件工程上面对类似界面点击这些都已经有了成形的工具,但是说实话国内软件业掌握的还不怎么样。当然也因为有很多不完善。
通过持续的反复测试,说白了不管是人还是机器,更多的经验和体力投入都能获得更好的效果。
7、安全管控
安全管控,现在安全组做的那些事情,包括用安全工具来扫描、找红帽组织来,其实都是基于行业经验来做到监理的角色。当然软件开发,本质还是一个智慧的事情,比如你家盖房子,你知道安装了窗户,需要有锁,而且锁必须在房子里面,不能在外面,低楼层需要安装防盗窗,防盗窗必须比一个正常的人要窄,这些都是经验。有很多现成的经验,需要在程序员开始干活之前就要掌握,其实不应该假设程序员什么都懂,其实他们很萌的。我刚开始写web的时候,那个时候没有往安全方面去想,因为之前一直做的是windows界面,不同窗口之间无所谓安全的事情,但是做web的时候,真的做了那种除了登录页面之外的页面也可以不要登录,敲个地址就能进去的low事儿,后来自己发现了,才从web的原理着手去了解了这样的问题,但是这个事情,终归是个意识和见识问题。大部分不干坏事的人不知道怎么干坏事,所以大家还是需要多学习。
然后就是一个好的基础框架,开发规范,很多公司程序员并不太了解这些,但是它们也不出轨,比如单点登录就帮他们解决了这个问题,因为架构上要求一个用户至少是登录的。
这里特别要提到接口,通常很多人做完接口就不管安全了,因为它不好测,也看不见嘛,但是这一块通常需要被重视。不过像什么WebService的标准里面都有一整套安全规范,当然除了大公司用之外,大家可能掌握的也不多。
8、性能规划
性能,是个数学问题吗?你先知道一共有多少的性能压力,你把小轱辘的轮子放在卡车下面自然是承受不了的。现在比以前好多了分布式计算让性能从单一计算机性能瓶颈上分解出来,但是分布式。。。。通常适用于可以分布式的事情。。。
其实在我们常见的场景中,无非是web性能和数据库性能,web性能现在大家都是用负载均衡来分开的,其实,很多时候傻逼的程序员干的蠢事需要服务器cpu来买单的事情也不少见。性能出问题,大多出现的问题,比如耗时的程序在工作,比如网络慢了,进行IO操作了,访问数据库了,跨边界的操作通常容易导致性能问题。比如访问内存的速度通常和访问数据库都不是一个量级的。那么在一个for循环里面访问数据库就是一个比较不合适的做法。那么一次性读取后再for也许能帮到你,当然也不是所有的场景都如此。还有就是良好的算法功底,比如一个循环的算法复杂度是O(n),而一个哈希表的算法复杂度是O(1),通常大家都不需要自己去写这些,但是选择合适的数据结构来处理问题,变得很重要。
至于你说你的服务器应该买多牛逼的,那我就不知道了,压力测出来之后,看着买能买得起的最贵的,然后调程序去吧。