首页 > 编程语言 >程序员基本认知

程序员基本认知

时间:2023-07-16 10:45:24浏览次数:34  
标签:基本 重构 例程 代码 认知 程序员 API 测试 Bug

内容来至: 人月神话,代码大全,程序员修炼之道

架构认知

Easier To Change

优秀的设计比糟糕的设计更容易变化,为你指向正确的设计方向。

可逆性

想想薛定谔的猫,把你的代码比喻为装100只猫的盒子,需求比喻为猫的话,想想你的代码为多少可能提供了支持?

因为改变是最稳定的,所以永不做最终决定,保持自身的可逆性是最理性的。

让你的代码具备“摇滚”精神:顺境时摇摆滚动,逆境时直面困难。

Don't Repeat Yourself

在一个系统中,每一处知识都必须单一、明确、权威地表达。我们要努力的方向,应该是孕育出一个更容易找到和复用已有事物的环境,而不是自己重新编写。

知识不仅仅等同于一段代码,可以把知识理解为某个抽象的行为或信息。行为可以有不同的变体,但是不管是信息还是行为,如果其中一个需要变化,那么其它的所有变体也需要变化。

重复的坏处,一改全该,发生一次错误的可能被放大了 N 倍。

比如:

  1. 代码重复,我们在多处粘贴复制同一个逻辑完成同一件事情。

    如果使用同样的逻辑,处理不同的两个行为,那么其并没有发生重复。

  2. 文档重复,注释和代码逻辑的重复。
  3. 数据结构的重复,线对象{起点,终点,长度} 其中长度就违背了DRY,因为起点,终点已经决定了长度。
  4. API 重复,API 的核心就是重复,一端变化另一端也必须变化,缓解策略。
    1. 内部 API: 对于内部 API,去找个工具,用来将 API 描述成一种中立的格式。这些工具通常能生成文档、模拟 API、功能测试。之后还可以生成不同语言的 API 客户端。理想情况下,这个工具会把 API 保存在一个中心仓库中,以便不同的团队共享。
    2. 对外 API: 使用 API 规范,这样可以方便将 API 规范导入本地内部 API 所使用的工具中。
  5. 开发工作的重复,加强沟通。

正交性(解耦,内聚)

就像两条垂直相交的直线,对于两个或多个事物,其中一个的改变不影响其他任何一个。

原型

使用原型来研究那些存在风险的东西,任何之前没有尝试过或对最终系统来说很关键的东西,任何未经证实、实验性或可疑的东西,以及任何让你不舒服的东西。

比如: 架构,新功能,第三方工具,性能问题,用户界面设计。

领域语言

语言之界限,即是一个人世界之界限。

使用问题域的语言来工作,会引起更好的思维扩展。所以有时可以使用现有的语言创造新的领域语言,或者直接创建一门新语言。

职业认知

怀揣感恩

计算机迅猛的发展,给我提供了很多的选择与可能。当代很多事物都基于其发展,让我获得了学习类似新时代自然规律的机会,对此我始终怀揣着感恩之心。

主动出击

机会总是在主动的人手上,在这个行业尤为明显。学习是一切的成本,这个行业已经给了我们很多的选择,不要抱怨当下,争取做个主动的人。

负责

责任意味着你对存在风险的事物的积极认同与承诺后所产生的义务。所以,当你犯错或作出错误判断时,要勇于承担责任,并积极善后。

尽量提供补救的选择,别找接口。当你想搪塞他人前,先想想你被搪塞时的感受。

软件的熵

软件开发总是不同的人,将不同的代码添加到同一个项目中,源代码,开发团队的无序化就是软件的熵。

破窗理论表明,少数无序的事情会招致更大的混乱,激增软件的熵。所以要做那个小心修补破窗的人,而非破窗者。

睁大眼,做变革的催化剂

事在人为,不是所有的想法所有人都配合你,可以轻松实现的。当你坚信所做的是对的,那就做变革的催化剂,让那些你请求帮助的人都认为自身是受益者,这样你才可以成功。

催化剂的责任很大,所以你要睁大眼睛看清楚未来和鼓足勇气前行。

争做变革的催化剂,而非破窗者!

够好即可的软件

如果不知道目标在何处,那你永远无法到达目的地。

尝试让用户参与权衡,将质量的作为需求。

知识组合

投资知识,收益最佳。尤其像在发展如此迅猛的计算机行业中,今日名花,很可能的成为昨日黄花。

这个行业的知识组合太像金融投资了,时效性尤其重要。可以向金融投资学习如何管理风险。

大多知识都需要通过网络自学,这需要具备强大的批判精神。

交流

我们需要和多个层面(计算机,同事,客户,老板)交流,所以交流十分重要。但并不是所谓的交际,而是单纯的信息传递。

一些要点: 了解听众,明白自己想说什么,选择时机,挑选讲述风格,包装内容,让听众参与,做倾听者,回应别人

项目管理认知

项目不只是软件,它是用户,团队,产品的统一

没有银弹

所有软件活动包括根本任务——打造由抽象软件实体构成的复杂概念结构,次要任务——使用编程语言表达这些抽象实体,在空间和时间限制内将它们映射成机器语言。

之所以没有银弹,是因为主要任务占开发时间的 9/10, 并且其花费的时间占比似乎无法被降低。并且大部分解决方案都针对于次要任务上,主要任务没有被重视。

银弹的希望寄托于加快构造抽象概念的技术上,比如原型开发,迭代开发,外包

人月神话

增加人数自然会增加项目的熵,如果这些人解决问题造成的正面影响大于所产生的熵,那么增加人数才有意义,人月才有可能成为现实。

而实际上,只有增加那些少数解决主要任务的人才会成为可能,但是现实却是为项目增加大量解决次要任务的人,这往往使得人月成为神话。

精简,稳定,专业的队伍

解决主要任务需要一小群稳定,精炼,专业的人就够了。

但在大项目中,解决次要问题仍需要大量的人,这就需要给予核心队伍更多的权利,雇佣更多的人节解决次要问题。

估算

通过估算避免意外,首先要弄清楚你想要避免多大的意外(估算的精度范围)。

如何估算?

  1. 理解在问什么: 精度问题,问题域的范围。
  2. 对系统建模: 当你理解了被问的问题时,就开始为之建立一个粗略的思维模型框架。建模会给估算过程引入不准确性。这不可避免,但也是有益的。你在用模型的简单性来换取精确性。在模型上加倍的努力可能只会换来精度上的微小提升。经验会告诉你何时应停止精炼。
  3. 把模型分解成组件: 一旦得到了模型,就可以将其分解为组件。你需要发掘出描述这些组件如何交互的数学规则。有时候组件向最终结果贡献的值是累加上去的,但有些组件提供的则是乘法因子,它们会更复杂。你会发现每个组件通常都有一些参数,这些参数会影响组件对整个模型的贡献。在这个阶段,只要确定出各个参数就行了。
  4. 确定每个参数的值: 你应该用一个合理的方法来计算这些关键参数。例如在队列的例子中,最好试着度量一下现有系统的实际事务到达率,或者找到一个类似的系统度量一下。
  5. 计算答案: 在计算阶段,你可能会得到一些奇怪的答案。不要急于否定。如果计算是正确的,那么错的可能是你对问题的理解,或者模型是错的。这是有价值的信息。

我们应该记录,培养自己的估算能力,以此提高估算项目进度的能力。

提高估算能力的方法有:

  1. 将估算结果转换为一个范围,分散不确定性。
  2. 确定一个项目的时间表的唯一方法,通常来自于在这个项目上获得的经验。所以通过增量开发,不断的在每个迭代环节中吸取经验,是有助于提高估算准确度的。

需求分析认知

需求是待挖掘的

客户是为了解决问题而给程序员提出需求,往往是不准确,不完美的。程序员的任务是协助客户节解决问题,挖掘出真正的需求。

一些挖掘需求从的方法: 从反馈循环中挖掘,以用户的角度解决问题

需求说明书是给开发者的

减少开发者在编程期间自行决定需求。明确的需求说明书免得你去猜测用户想要什么。

需求说明书只是让开发者明白要制作什么功能的,而非给客户和架构师看的。

因为需求说明书不能完全替代交付的产品,所以无法获得准确的客户反馈。应该迭代开发,给客户交付产品来需求获取反馈。

需求说明书也不应该太多牵扯底层代码,架构的内容,只做到表明需要完成的功能是什么即可。

编码认知

纯文本

将信息使用纯文本保存,纯文本具备很强的易用性,传播性。

Shell

shell 是开发者的工作台!

加强编辑器

你大部分时间都在使用它编写代码,一个快捷键的使用可能剩下你很多时间。挖掘,改进你的编辑器,让它成为开发利器。

版本管理器

把版本控制视为项目中枢!

调试

代计算机系统仍有局限性,能干你让它干的事情,却不一定是能干你想让它干的事情。

调试步骤:

  1. 调试心态
    1. 去解决问题,而不是责备: Bug 是你的错还是别人的错并不重要。无论是谁的错,问题仍然要你来面对。
    2. 不要惊惶: 保持冷静,真想想,到底什么会导致它们那个样子。并且不要认为不可能,不要太短视,发掘问题的根本原因,而不仅仅停留在问题的表面现象。
  2. 收集相关数据,弄明白发生了什么: 堆栈信息,第三方库的Bug公告,人为测试,询问导致 Bug 的用户。
    1. 查看错误信息
    2. 边界测试
    3. 如果堆栈太深,使用二分法,尽快找到具体的故障点
    4. 输出日志或跟踪信息
    5. 排除法,排除最不可能的(不要在没有不大有意义的事情上浪费时间)
    6. 不要假设,要证明
  3. 复制 BUG (虽然有些 Bug已经到了合法生殖的年龄): 在修改代码前现在测试中复现它。当强制自己对暴露 BUG 的环境进行隔离时,就能高提高对 Bug 修复的洞察力。

调试工作的清单:

  1. 被报告的问题是潜在的 Bug 的直接结果,还是仅仅是一种症状?
  2. 真的是你所使用的框架的 Bug 吗?是 OS 的问题吗?还是仅仅是你代码的问题?
  3. 如果你要向同事详细解释这个问题,你会怎么说?
  4. 如果怀疑的代码通过了单元测试,那么测试是否足够完整?如果使用这些数据运行测试,会发生什么?
  5. 导致这个 Bug的条件是否存在于系统的其他地方?还有其他 Bug 处于幼虫期等着孵化吗?

死掉的程序不会说谎

捕获再释放只适合用在鱼身上

尽早崩溃,不要制造垃圾。如果你不知道如何处理异常,那就让他尽快崩溃,然后思考如何处理它!

契约式设计

契约规定了你的权利和责任,同时也规定了对方的权利和责任。另外,如果任何一方不遵守契约,还会面对一个针对后果的协议。

针对函数的契约而言:

  1. 前置条件: 为调用这个例程,必须为真的是什么?例程的需求。一个例程永远不应该在前置条件被违反的时候被调用。传递良好的数据是调用者的责任。
  2. 后置条件: 例程保证要做的是什么?例程完成时世界的状态。
  3. 不变式: 从调用者的角度来看,类会确保该条件始终为真。在例程的内部处理期间,可以不遵守不变式,但是当例程退出并将控制权返回给调用者时,不变式必须为真。

所以如果调用者满足了例程的所有前置条件,则例程应保证在完成时所有后置条件和不变式都为真。如果任何一方未能履行契约,就会调用(之前已经同意的)补救措施——可能是抛出异常,或者程序终止。不管发生什么事,毫无疑问,不能履行契约都是一个 Bug。

参数验证是谁的责任呢?

在契约中可以把责任无情的抛给调用者,但是双层保险不是更好吗?但是与其让他溃烂不如尽早崩溃好了。而且双层保险同时违背了 DRY 原则。所以责任还是在调用者身上,而且本来就是它主动调用的!

断言式编程

似乎每个程序员在职业生涯早期,都一定会记住一句魔咒: 这件事绝不会发生……

  1. 使用断言去预防不可能发生的事情。
  2. 注意断言的副作用
  3. 保持断言常开

保持资源平衡

做到有始有终,对于嵌套的资源要做到释放资源的顺序与分配资源的顺序相反,对于多次分配的同一组资源要做到始终以相同的顺序分配它们,来避免死锁发生。

使用代码或工具监控资源平衡。

解耦

解耦就是将代码更具有正交性,更独立。以下是一些用于解耦的工具:

  1. Tell Don't Ask: 我们不应该根据对象的内部状态做出决策,然后更新该对象。这样做完全破坏了封装的优势,并且在这样做时,也会把实现相关的知识扩散到整个代码中。而是应该在合适的对象上将 API 暴露出来。
  2. 不要链式调用方法: 除非是语言附带库中的代码。
  3. 避免全局数据: 任何可变的外部资源都是全局数据,如果全局唯一非常重要,那么将它包装到API 中。
  4. 避免继承: 尽量使用接口

配置

使用外部配置参数化应用程序,并且配置最好是动态的,将配置服务化。无论采用何种形式,配置数据都会驱动应用程序的运行时行为。当配置值更改时,不需要重新构建代码。

重构

四境所见,尽是变迁朽腐……

重组现有代码实体、改变其内部结构而不改变其外部行为的规范式技术。

重构应该伴随整个项目周期,当你有所长进或发现某处违背 DRY...规范时,就应该去重构。

做到尽早重构,经常重构。

一些简单技巧,可以用来确保进行重构不至于弊大于利:

  1. 不要试图让重构和添加功能同时进行。
  2. 在开始重构之前,确保有良好的测试。尽可能多地运行测试。这样,如果变更破坏了任何东西,都将很快得知。
  3. 采取简短而慎重的步骤:将字段从一个类移动到另一个类,拆分方法,重命名变量。重构通常涉及对许多局部进行的修改,这些局部修改最终会导致更大范围的修改。如果保持小步骤,并在每个步骤之后进行测试,就能避免冗长的调试。

命名

  1. 保持词汇语意一致性。
  2. 好好取名,需要时更名。

测试认知

测试与找 Bug 无关

测试获得的主要好处发生在你考虑测试及编写测试的时候,而不是在运行测试的时候。

让测试驱动编码(TDD),针对契约测试。

要对软件做测试,否则只能留给用户去做

特性测试

一旦实现了契约和不变式(我们将把它们放在一起并称为特性),就可以使用特性来自动化我们的测试。最后要做的事情被称为基于特性的测试(使用代码表现特征,然后进行大量具体测试)。

基于特性的测试让你从不变式和契约的角度来考虑代码;你会思考什么不能改变,什么必须是真实的。这种额外的洞察力会对代码产生神奇的影响,可以消除边界情况,并突显使数据处于不一致状态的函数。

标签:基本,重构,例程,代码,认知,程序员,API,测试,Bug
From: https://www.cnblogs.com/ivanohohoh/p/17557543.html

相关文章

  • 每个程序员必读的经典书籍
    作为程序员,面对日新月异的技术,我们必须不断的坚持学习来拓展知识面,加深技术理解,提高自身竞争力。但是技术相关的书籍浩如烟海,如何选择成为摆在我们眼前的问题?今天我从编程语言、算法与数据结构、数据库、网络编程、软件开发等5个方面聊下有哪些经典书籍值得我们仔细阅读。在最后我......
  • GitHub标星百万的程序员转架构之路,竟被阿里用作内部晋升参考
    架构师架构师是很多程序员的奋斗目标,也可以说是职场生涯的一个重要选择方向,今天我就跟大家聊一聊如何从一个程序员成长为一个架构师。首先我们先来看看架构师的定义到底是什么?系统架构师是一个不仅需要主持整体又得需体察局部瓶颈并且依据详细具体的业务情景给出处理方案的团队领导......
  • 程序员神器——cmder
    程序员神器——cmder简介Cmder是一款软件包,它的诞生纯粹是出于对Windows上缺乏优秀的游戏机模拟器的无奈。它以出色的软件为基础,采用Monokai配色方案和自定义提示布局,从一开始就显得非常性感。特点便携,解压即可用自带git、ls、curl等命令可设置命令别名丰富的颜色主题(Sol......
  • 数据类型、基本数据类型转换
    基本数据类型整型【byte,short,int,long】byte1 字节short2 字节int4 字节【默认】long8 字节(声明long型常量时,需在常量后加l或L)浮点型【float,double】float4 字节(保留8位有效数字)(声明float型常量时,需在常量后加f或F)double8 字节(保留17位有效数字)【默认】说明:1)浮点数......
  • MySQL学习-基本操作
    1.数据库操作创建数据库createdatabasetest;查看数据库showdatabases;进入数据库usetest;删除数据库dropdatabasetest;2.表格操作创建表格 createtabletable1(namevarchar(20),date1date)删除表格droptabletest1修改表格表项altertabletable1modif......
  • DBGridEh 基本操作
    导出到Excel等文件类型1.导入导出引用单元useDBGridEhImpExp;类型说明类型名称说明TDbGridEhExportAsText导出到文本文件TDbGridExportAsUnicodeText导出到Unicode文本TDbGridEhExportAsCSV导出到CSVTDbGridEhAsHtml导出到HTMLTDBGridEhAsRTF......
  • day03 链表基本操作
    前置知识,链表数据结构1.移除链表元素移除链表元素不难,只需要把前一个结点的下一节点指向下一个节点的下一节点如果当前遍历的节点与所给值相等,则需要移除此元素,移除元素是将上一节点的next域设置为当前节点的next,当前节点后移一位如果当前遍历的节点值不等于所给值,则前驱......
  • 深度学习(六)——神经网络的基本骨架:nn.Module的使用
    一、torch.nn简介官网地址:torch.nn—PyTorch2.0documentation1.torch.nn中的函数简介Containers:神经网络的骨架ConvolutionLayers:卷积层Poolinglayers:池化层PaddingLayers:PaddingNon-linearActivations:非线性激活NormalizationLayers:正则化层......
  • 大数据Flink之基本架构
    第二章Flink基本架构2.1 JobManager与TaskManagerFlink运行时包含了两种类型的处理器:JobManager处理器:也称之为Master,用于协调分布式执行,它们用来调度task,协调检查点,协调失败时恢复等。Flink运行时至少存在一个master处理器,如果配置高可用模式则会存在多个master......
  • 搞清楚服务器的基本架构
    DELL服务器拿到手后,第一步应该干什么?当然是先安装操作系统,但是安装之前,应该先设置iDrac系统吧?但DELL官网上介绍的是先设置如下使用DellLifecycleController设置DellPowerEdge服务器设置好后,需要使用虚拟介质,在iDRAC6、iDRAC7、iDRAC8和iDRAC9上使用虚拟介质功能然后......