【ArchSummit 】架构顶层设计视角梳理从0到1打造大模型体系的路径! 了解详情
写点什么

大师级程序员,都用哪些工作法?(下)

  • 2019-05-31
  • 本文字数:3436 字

    阅读完需:约 11 分钟

大师级程序员,都用哪些工作法?(下)

你好,我是郑晔,《10x程序员工作法》专栏作者,火币网首席架构师。


程序员是一个忙碌的职业,与这个职业联系在一起的词儿,通常是忙碌、加班、熬夜、过劳、亚健康……当忙碌成为了主旋律,“高效”一词就自然浮出了水面。


可是,程序员工作效率是由编程能力决定的吗?答案是“未必”。


这些年,我一直在研究一件事儿:为什么那些大师级程序员,可以兼顾 N 倍于一般人的工作,还有条不紊?他们究竟用了什么工作法?根据我的观察与总结,他们往往绕不开四个工作原则。


「大师级程序员,都用哪些工作法?(上)」中,我给大家介绍了“以终为始”和“任务分解”这两个工作原则,相信你对 DoD、精益创业、微操作等有了一定的认知。下面,我给大家继续介绍另外两个工作原则:沟通反馈和自动化。

沟通反馈

可视化:技术雷达

ThoughtWorks 技术雷达用来追踪技术,通过可视化的方式给程序员提供了一种更系统、直观地了解新技术的方式。



在雷达图中,组织技术的方式也并不复杂。每一项技术表示为一个 blip,也就是雷达上的一个光点。然后用“象限”(quadrant)和“圆环”(ring)组织这些 blip。


其中,象限表示一个 blip 的种类,目前有四个种类:技术、平台、工具和语言与框架。圆环表示一个 blip 在技术采纳生命周期中所处的阶段,目前这个生命周期包含四个阶段:采用(Adopt)、试验(Trial)、评估(Assess)和暂缓(Hold)。


雷达图是一种很好的将知识分类组织的形式,它可以让你一目了然地看到了解所有知识点,并根据自己的需要,决定是否深入了解。


比如,每次技术雷达发布之后,我会特别关注一下“采用”和“**暂缓”两项。“采用”**表示强烈推荐,我会去对比一下自己在实际应用中是否用到了,比如,在 2018 年 11 月的技术雷达中,事件风暴(Event Storming)放到了“采用”中。


“暂缓”则表示新项目别再用这项技术了,这会给我提个醒,这项技术可能已经有了更优秀的替代品,比如,Java 世界中最常见的构建工具 Maven 很早就放到了“暂缓”中,但时至今日,很多人启动新项目依然会选择 Maven,多半是不了解技术趋势。


在我看来,雷达图不仅仅适用于组织,也可以适用于团队。


我也曾经按照雷达图的方式将自己的团队用到的技术组织起来。把最需要了解的技术必须放在内环,比如:一个 Java 项目,我会要求程序员了解 Java,向外扩展的就是你在这个团队内工作会逐渐接触到的技术,像 Docker 这种与部署相关的知识。至于最外面一层,就是被我们放弃掉的技术,比如,Maven。


这样一来,团队成员可以更清晰地了解到团队中所用的技术。当有新人加入团队时,这个雷达可以帮助新人迅速地抓住重点,他的学习路径就是从内环向外学习。


出自第23讲|可视化:一种更为直观的沟通方式

Fail Fast

写程序有一个重要的原则叫 Fail Fast,遇到问题,尽早报错。


很多人以构建健壮系统为由,兼容了很多奇怪的问题,反而会把系统中的 Bug 隐藏起来。靠 debug 来定位问题是最为费时费力的一种做法,别怕系统有问题,有问题早点报出来。


举个例子,我做了一个查询服务,可以让你根据月份查询一些信息,一年有 12 个月,查询参数就是从 1 到 12。


问题来了,参数校验应该在哪做呢?如果什么都不做,这个查询参数就会穿透系统,传到你的数据库上。如果传入的参数是合法的,当然没有任何问题,这个查询会返回一个正常的结果。但如果这个参数是无意义的,比如传“13”,那这个查询依然会传到数据库上。


事实上,很多不经心的系统就是这么做的,一旦系统出了什么状况,你很难判断问题的根源。在这个极度简化的例子里,你可以一眼看出问题出在输入参数上,一旦系统稍具规模,请求来自不同的地方,这些请求最终都汇集到数据库上,识别来源的难度就会大幅度增加。尤其是系统并发起来,很难从日志中找出这个请求的来源。


你可能会说,“为了方便服务对不同数据来源进行识别,可以给每个请求加上一个唯一的请求 ID 吧?”看,系统就是这么变复杂的,我经常调侃这种解决方案,就是没有困难创造困难也要上。当然,即便以后加上请求 ID,理由也不是这个。


稍有经验的人都知道,参数校验应该放在入口的位置上,不合法的请求就不让它往后走了。这种把可能预见的失败拦在外面的做法就是 Fail Fast,有问题不可怕,让失败尽早到来。


上面这个例子很简单,我再给你举一个例子。如果配置文件缺少了一个重要参数,比如,缺少了数据库最大连接数,你打算怎么处理?很多人会选择给一个缺省值,这就不是 Fail Fast 的做法。既然是重要参数,少了就报错,这才叫 Fail Fast。


出自第27讲|尽早暴露问题: 为什么被指责的总是你?

自动化

SOLID 原则

《敏捷软件开发:原则、实践与模式》的作者 Robert Martin 提出的面向对象设计原则:SOLID,为软件设计的目标“高内聚、低耦合”提供了很好的指导。“SOLID”其实是五个设计原则的缩写,分别是


  • 单一职责原则(Single responsibility principle,SRP)

  • 开放封闭原则(Open–closed principle,OCP)

  • Liskov 替换原则(Liskov substitution principle,LSP)

  • 接口隔离原则(Interface segregation principle,ISP)

  • 依赖倒置原则(Dependency inversion principle,DIP)


什么是单一职责原则呢?Robert Martin 把单一职责原则的定义修改成“一个模块应该仅对一类 actor 负责”,这里的 actor 可以理解为对系统有共同需求的人。


这可能不是很好理解,我举个例子你就懂了。在一个工资管理系统中,有个 Employee 类,它里面有三个方法:


  • calculatePay(),计算工资,这是财务部门关心的。

  • reportHours(),统计工作时长,这是人力部门关心的。

  • save(),保存数据,这是技术部门关心的。


之所以三个方法在一个类里面,因为它们的某些行为是类似的,比如计算工资和统计工作时长都需要计算正常工作时间,为了避免重复,团队引入了新的方法:regularHours()。


接下来,财务部门要修改正常工作时间的统计方法,但人力部门不需要修改。负责修改的程序员只看到了 calculatePay() 调用了 regularHours(),完成了他的工作,财务部门验收通过。但上线运行之后,人力部门产生了错误的报表。


如果你问程序员,为什么要把 calculatePay() 和 reportHours()放在一个类里,程序员会告诉你,因为它们都用到了 Employee 这个类的数据。


但是,它们是在为不同的 actor 服务,所以,任何一个 actor 有了新的需求,这个类都需要改,它也就很容易就成为修改的重灾区。更关键的是,很快它就会复杂到没人知道一共有哪些模块与它相关,改起来会影响到谁,程序员也就越发不愿意维护这段代码了。


人的大脑容量有限,太复杂的东西理解不了。所以,我们唯一能做的就是把复杂的事情变简单。我在“任务分解”模块中不断强调把事情拆小,同样的道理在写代码中也适用。单一职责原则就给了你一个指导原则,可以按照不同的 actor 分解代码。


出自第34讲 | 你的代码是怎么变混乱的?

领域分层

分层,实际上是在构建抽象,构建抽象,最核心的一步是构建出你的核心模型,核心模型就是表达你业务的那部分代码。换句话说,别的东西都可以变,这部分不能变。


这么说有点抽象,我们回到前面提到的三层架构的演变:REST 服务的兴起,让 Controller 逐渐退出了历史舞台,资源层取而代之。换句话说,访问服务的方式可能会变。


放到计算机编程的发展中,这种趋势就更明显了,从命令行到网络,从 CS(Client-Server) 到 BS(Browser-Server),从浏览器到移动端。所以,怎么访问不应该是你关注的核心。同样, 关系型数据库也不是你关注的核心,它只是今天的主流而已。从前用文件,今天还有各种 NoSQL。


如此说来,三层架构中的两层重要性都不是那么高,最重要的是剩下的部分,我们习惯上称之为服务层,但这个名字并不能很好地反映它的作用,更恰当的说法是“领域模型”(Domain Model),它便是我们的核心模型,也是我们做软件设计时,真正应该着力的地方。


为什么“服务层”不是好的说法呢?这里会遗漏领域模型中一个重要的组成部分:领域对象。很多人理解领域对象有一个严重的误区,认为领域对象属于数据层。数据存储只是领域对象的一种用途,它更重要的用途还是用在各种领域服务中。


由此还引出另一个常见的设计错误,领域对象中只包含数据访问,也就是常说的 getter 和 setter,而没有任何逻辑。如果只用于数据存储,只有数据访问就够了,但如果是领域对象,就应该有业务逻辑。比如,给一个用户修改密码,用户这个对象上应该有一个 changePassword 方法,而不是每次去 setPassword。


出自第35讲| 总是在说MVC分层架构,但你真的理解分层吗?


内容选自极客时间10x程序员工作法专栏


2019-05-31 17:5112594
用户头像

发布了 22 篇内容, 共 13.6 次阅读, 收获喜欢 49 次。

关注

评论

发布
暂无评论
发现更多内容

你知道Redis有哪些潜在的阻塞点吗

芥末拌个饭吧

后端 redis 底层原理 10月月更

【小程序】一文读懂微信小程序登录流程及获取手机号

国服第二切图仔

小程序 前端 10月月更

细说nodejs的path模块

coder2028

node.js

面试官:你说说JavaScript中类型的转换机制

CoderBin

JavaScript 面试 前端 类型转换 10月月更

Nodejs:ESModule和commonjs,傻傻分不清

coder2028

node.js

在线问题反馈模块实战(七):安装部署swagger2

bug菌

springboot 项目实战 10月月更

【LeetCode】无法吃午餐的学生数量Java题解

Albert

算法 LeetCode 10月月更

深入nodejs的event-loop

coder2028

node.js

钛媒体 | 发布PaaS平台2.0,元年科技通过自主技术撬起更大市场

元年技术洞察

媒体 PaaS

在线问题反馈模块实战(九)​:实现图片上传功能(下)

bug菌

springboot 项目实战 10月月更

HashMap源码分析(三)

知识浅谈

HashMap底层原理 10月月更

Visual Studio (VS2017)提交代码到Git服务器流程(GitCode)

DS小龙哥

10月月更

银斯微推出跨平台APP生成、发布Non-Stop云服务“W-Hive”

科技热闻

ScheduledThreadPoolExecutor踩过最痛的坑

小小怪下士

Java 程序员

从P5~P8!最适合在职Java程序员学习提升路线大公开!

Java永远的神

程序人生 后端 架构师 java程序员 Java学习路线

Kyligence 当选 Gartner 2022 中国数据管理 Cool Vendor

Kyligence

Gartner 数据管理

koa实战

coder2028

node.js

深度解读Webpack中的loader原理

Geek_02d948

webpack

Webpack中的plugin插件机制

Geek_02d948

webpack

Webpack插件核心原理

Geek_02d948

webpack

Webpack完整打包流程分析

Geek_02d948

webpack

深入浅出--Linux基础命令知识(总结,配图文解释)

木偶

Linux ubuntu 10月月更

一文梳理2048小游戏从开发到上云全流程

华为云开发者联盟

云计算 游戏开发 华为云 企业号十月 PK 榜 2048小游戏

从零到一搭建一个属于自己的博客系统(弌)

木偶

django 前端 10月月更

车联网移动场景MQTT通信优化实践

EMQ映云科技

车联网 物联网 IoT mqtt 10月月更

企业架构-了解分布式

Marvin Ma

企业架构 分布式系统 凤凰架构 书籍拆解

如何定义LED显示屏与OLED显示屏

Dylan

LED LED显示屏 OLED

建木v2.5.7发布

Jianmu

DevOps 持续集成 CI/CD 自动化运维

在线问题反馈模块实战(八)​:实现图片上传功能(上)

bug菌

springboot 项目实战 10月月更

数据量剧增怎么办?Redis切片集群了解一下

芥末拌个饭吧

后端 redis 底层原理 10月月更

Python继承还不会,看这篇就够了

芥末拌个饭吧

继承 python 3.5+ 10月月更

大师级程序员,都用哪些工作法?(下)_文化 & 方法_郑晔_InfoQ精选文章