深夜睡不着,看看技术论坛,发现大多的程序员都在论坛里面吐槽,宣泄。然后就是各种黑段子自嘲,贬低程序员这个职业。
当然,不知道是有意还是现在的网络文化所致,大家都喜欢用夸张的言论甚至完全相反的言论去表达对一些事务的不满,总是喜欢骂这个是 SB,那个是 SB。
于是乎去看看其它的论坛,发现情况大有不同,特别在设计之类的圈子里面更是自认为是艺术家了,不过有一点不变,总是喜欢吐槽其它部们的同事,说别人是 SB。
但是,写代码何偿也不是一种设计呢?每天写的那么多行代码中,也充满了一个 “艺术家” 对代码的品质追求!
风格设计
首先,编码风格上,需要具体到开发语言,通常会有不同的流派,比如php里面大众认可的都是小写加上下划线去写方法,java里面就是驼峰写法,如果反过来用也没问题,但是会觉得很奇怪
每种语言都可能存在几种流派,可以选择主流方式,一般来说的话,可以更接进于语言的核心思想,另外可以多看看优秀源码,从源码中学习。
本人就喜欢Golang,内置的gofmt和很多规范基本上就让程序员没得选择权的使用了同一种编码风格,当然有很多人也是因为这种约束拒绝这们语言的,就不做争论了。
风格包括名称:命名空间,类名,方法名,变量名等,没有统一的标准,尽量使用简单的英文单词,不要太长,认人一看就懂,结构化的层次,如包->类->方法等,都可当作上下文来使用,可以省略掉很多多余的单词也能一眼就能看明白用途,所以要合理使用。
结构上的设计就需要根据实际情况来发挥了。一般来说,面向对象和面向过程、面向服务等等在代码结构上的设计也会有很大的差别,对于风格上的设计来说,标准就是:易读、易用、易猜,虽然很简单,但要真正做到好,还需要花费不少功夫的。
接口(SDK)设计
接口设计,这里的接口设计指的是单个程序内部使用的接口(外部的我个人命名为API,呆会再说),可以在集成编译器中有代码提示的那种。
接口设计,网上搜的话,会有多种多样的原则,其实这个和上面所说的结构设计是关联较大,主要核心思想是:高内聚,松耦合。但个人感觉理想状态下的“高内聚,松耦合”只是一种空想的假设,并不存在完美的高内聚,松耦合,主要是因为实际应用中的业务往往没那么单一,可能极其复杂,界限难以规划,这些就需要考虑各模块间的复杂程度做综合估量了。
有一种编程思想称为面向接口编程,其实我也不是太明白这个编程思想是什么,简单的看了一下,感觉比较像TDD里面的思想:“功能未做,接口先行”,先定义接口规范,确认后,再对其进行各种实现,那么在这种开发思想下,搞敏捷就比较容易了,编写相应的MOCK,开发过程中不用管别人接口到底有没写好,只要有规范,搞完之后执行单元测试即可了。所以接口一定要设计成可测试的。
另外还有一点,最近发现的比较多,很多项目喜欢在接口命名头上加个I(Interface),听起来像iPhone之类的,然后在依赖管理中使用命名规则进行反射或注入等,并将其设计理念称之为“规则(约定)优于配置”,比如Spring,angular等,使用这个“优于”的条件这是建立在理解的基础上,如果不理解,可能换个名字什么的让程序不能用了而感到莫名奇妙,所以这里也可以说成“习惯优于配置”。
接口设计的命名规范应该还是比较好定义的,在Java中还有抽象类,抽象类通常设计对象,接口设计能力集,有了这些上下文,命名应该尽量从简,能使用动词,就不要使用动词加名词的组合,动词不宜太多样化,尽量保持统一即可。
API设计
这里我说的API的设计就是指不同部件之间的接口设计,一个组件提供服务给第三方调用,这样的设计要考虑的因素实在太多,根据API的消费者可以分为对内API、对外API,设计需要考虑到用户安全性如访问权限、数据范围等。根据API使用的协议来分,主要又有HTTP、RPC、SOAP、SOCKET、RESTFUL等等,每种协议其适用性与应用场景也会有所不同,需要考虑API消费者使用的技术栈,性能要求等等。
一般来说,做为API消费者,代码可能就是三个部分组成:
init() //初始化
result=inovke(args) //调用接口返回结果
use(result) //使用结果
所以,设计时,尽量要遵循:
简单
:凭直觉即可知道API的功能作用,这点是各种设计通用的。容错高
:各种数据都能智能处理,输入数据范围广。无副作用
:只对功能描述的范围起作用,不会有其它影响。明确返回
:一致通用的返回方案能够让消费者便于处理。
API设计时,由于通常要提供给第三方使用,所以尽量使用公认的标准的协议,这样才能满足不同技术栈的需求。
大部分语言中都自带Remoting技术最好是不要使用,RPC的话也要考虑是否每个消费者都能容易使用,通常来说HTTP/(JSON,XML)的方式可能会成为标配,很多API会按RESTFUL的规范进行规划。
基于HTTP的通信可能会在性能上不能满足一些大并发业务的极端场景,所以很多基于Socket的自制协议又横空出世,比如Netty,很多对性能有高要求的厂商将自身的协方议封装到SDK里面,要提供出去,对外提供的SDK包括了自定义的接口集,结构体等,让消费者能够很方便使用,但缺点就是如果服务要升级,就要让所有的消费者升级配套的SDK。
服务设计
目前流行(热门,讨论的人多,几乎没见过实例)微服务架构。很多人认为微服务就是一个服务规划,其实在根本不存在云计算和微服务这样的名词以前,对软件架构上的分而治之的思想就已经存在了,只不过微服务的概念对于服务设计来说算上一次架构上的规范化与升级,微服务基于云,可以运行于云平台、容器内,服从云平台对资源的管理,变得非常可控与可管理。相对于老式的分布式,分而治之思想,有着思维上的突破,灵活化了运维管理与软件交付周期。
但是微服务并没看上去的那么美好,一个企业的软件架构如果想用微服务来重构,代价巨大不说,且说改变为微服务之后,是不是适合企业使用,单靠对于技术人员的能力要求可能传统的业务开发型并不是太合适,当然个人通过实操提升能力也是可以的。微服务
这里探讨一个服务设计中的一个服务编排问题,微服务化后,会增加服务之间通信的成本,但并不意味着会变得钝化,慢之类的,合理的服务编排,对于同步/异步任务的管理,可以很容易超越传统的串行化的服务。而且微服务后面的大数据处理、挖掘、以及各种的商业服务应用可以极大程度上提高产品的核心竞争力,这些都是传统的服务设计不具备的,所以说不要认为将功能分而治之就算是具有了微服务的思想了。
应用设计
应用则是直接面向用户的了,通常是UCD、产品、市场职能的人去进行设计与规划,做为程序员来说,可能并不那么直接,但我想一般来说至少技术的骨干成员或者Leader具有一定的发言的,其实如果公司不大,通常都是一人多责的。对于产品的总领导来说,不管是技术还是市场,对产品的方向来说,都是有一个总体目标轨道定位的,和技术的基本编程思想类似。技术上来说应当要对这个“总体作战方案”进行深化考虑分析。
之前的公司遇到一个比较开明的领导,成立业余技术组,探讨DDP技术驱动产品,需要技术人员具有一定的市场远见,主要是考虑目前的生产力虽然可以满足产品需求,但产品和市场不一定能从技术里面挖掘出价值,技术人员可自由发挥想法将想法付出实践,DEMO也好,原型图也行,让其它职能的人能够从一些“黑科技”中看出市场潜能,也算是一部分工作。
应用设计也没什么特殊技能,用户选择一款产品的理由往往不是功能点的数量,而是核心业务的质量,换位在用户的角度去思考反想如何提高应用的质量。从下往上,粒度越来越来大,设计底层时,要从高层倒排去慢慢考虑,设计高层时,要从底层去看业务与技术是否吻合,如果每次都使用“将就”、“临时解决”这种词去做应用,那么总有一天应用会久积成疾,仿佛什么需求加在应用上都会显得特别别扭。
小插曲,现在在设计应用时,如果是设计一个新应用,可以把埋点需求也考虑进去,这些是市场、产品比较关心的,因为优秀的代码强调复用性高,但市场人员不会理解,他们认为一个页面上两处相同功能也需要独立进行统计,可以更好的页面分析,所以,一些相同的功能点在有多个入口的情况下埋点就是一个小抵抗,当然这是个小问题,相信大多数人都能搞定这种小事了,只是想起来了忽然说下。
小总结
套一位数学家的话:All Models Are Wrong, but Some Are Useful,同样可以用到设计里面:所有的设计都是错的,但有些是有用的,对应具体的情况使用合理的设计,才能精准解决问题。请不要总是看很多科技文章说某某某系统、架构上使用了什么什么样的模型设计,就把别人的技术鼓吹到神一样的境界,而是要有想法的去反思,去比拟,这样才能有所成长,或是超越。
这句话还有一个意思就是,我们的软件设计不是固定的,在此时此刻或许可以解决目前的问题,但在彼时彼刻可能就完全没用,所以设计上,也需要做到能拥抱变化,这里在设计上基本上没有太多技巧可言,仅有一条技巧就是:遵循基本原则:低耦合,高内聚,这样在变化时需要重写,重构,业务改变,结构移接等需要时,这些基本思想会助你一臂之力。
所以不要总是自嘲了,写代码时,每当写一个方法、接口、服务时考虑了上面的种种,那我们就不再是代码的搬运工,而是代码的创造者、创新者。把代码重构培养成为一种习惯,这样会觉得很多以前想做又害怕做的事其实也并没有想象中的那么可怕。