浅谈软件工程师的自我修养

概述

“对于知识,要求知若渴;对于自己,要虚怀若谷。”优秀的软件工程师一定是在软件开发的道路上前行者。自学是其成长的一个重要手段,在自学的过程中,我们是可以通过考试的方式来收敛思绪,督促自己学习,从而提高自己的基本素质。诚然,原则和模式是软件工程质量的基石。但技术是工具, 是为人服务的,而不是相反的。我们不能为了迎合某种技术而束手束脚,让自己特别难受。与此同时,要让自己的能力发挥到极致,良好的心境是必须要有的,因为软件工程中的一个核心因素是人的因素。

诚然,在软件开发过程中,我们不仅要将自身内功修炼好,更应该 “用产品说话”。那么,在这个过程中,我们该如何保证开发的质量呢?在开发的过程中如何专注于自己擅长的事情呢?在本文中,我们将探讨软件开发过程中关于角色、重构和质量的问题。

角色

我们经常提一句话:革命工作只有分工不同,没有高低贵贱之分。这里的分工其实就是角色的划分。角色划分是为了让个体承担的工作量最小化,从而可以把我们从繁文缛节中解放出来,专注于自己擅长的事情。那么,在软件工程当中,这样的理念应该如何贯彻呢?

软件工作里面的脏活儿、累活儿一般是指技术老旧而不得不维护的一些工作。还有一些重复性强的工作也被称为脏活儿、累活儿。

对于这种活儿,一般工程师都想推脱掉。主要原因是认为做这类活儿技术提高的空间很小,再加上技术陈旧,这些技巧学会了以后也用不上,同时也比较枯燥。

这类工作的工程师一般是指派的。需要对相关的工程师进行一些必要的技术培训或者直接招收懂得相关技术的工程师加入工作。

效率和价值主要体现在帮助客户解决现有软件系统中的问题,或者添加新的功能。客户可能很少愿意购买一套崭新的系统,因为价格相对比较高,所以他们宁愿少花点钱去做些修修补补的工作,能够解决燃眉之急就可以了。

运维工作的价值是把已经开发出来的组件和系统集成起来统一的工作。是推出面向用户的软件系统产品的重要一步。我不认为是边角料的活儿。

运维相关的工作越简洁越清晰越好。这部分相关的文档一般是read me markdown的形式存放在软件系统的repo中。通过查看这些文档,应该可以自行部署整套系统。

系统部署一般会分几种类别,开发模式,qa模式,staging模式和生产模式。

业界对于软件开发过程中的角色有不同的理解和看法。笔者观点如下:

1.项目产品经理负责业务需求的处理,负责跟客户与开发团队打交道。

2.项目开发组长一定是全栈,需要统筹规划,与项目经理一起探讨需求分析,与开发组成员一起探讨开发设计,任务分配与开发实现。

3.前端工程师负责网络页面程序开发,手机端应用开发,桌面端应用开发等等。

4.后端工程师负责API设计与开发, 数据分析处理与消息推送。

5.运维工程师负责部署环境的搭建与看护。

6.针对具体的业务需求,还会有更细分的角色类别,比如说大数据工程师,算法工程师,AI工程师,机器学习工程,深度学习工程师,中间件工程师。

7.测试工程师负责系统集成后的业务需求案例测试。这一部分的输入跟开发团队的输入是一样的,都是用户的需求。输出则是需求案例对应的测试报告。而开发团队的输出就是整个软件系统。

重构

为什么我们需要对代码和设计进行重构?主要是因为我们发现了更好的做法,如效率更高,更容易维护等等。

简单的代码重构我们都比较熟悉,比如说你通过工具就可以做一些整理。

一般来说,重构是为了解决复杂度的问题。

现在比较头疼的一个话题就是对老产品的重构,一些老产品涉及到上千万行,上亿行的代码。

关于老产品整改的问题。如果只是缝缝补补的话,可能起不到化繁为简的目的。其实做类似这种工作的话,有一个比较可行的方案。就是把现有的产品当做一个成型系统也就是现有运行的产品,不要做大的改动,顶多就是修改bug。

然后以这些成型的系统为基准,去写新的系统。相当于参照一个大的白盒就写一个小的白盒,这样新的小的白盒质量上肯定比大的白盒性能上要有优势。

这样子按部就班去做的话,就会比较靠谱。

有朋友会说上面的做法是重写,字面意义上没错的。

实际上不矛盾。区别就是重构的方式应该从下往上还是从上往下。比如说我们现在大部分的重构都理解为从下往上来做。也就是感觉这个文件里头有坏代码的味道,然后就改这个文件,这样做是没有问题的。前提是这项工作的上下文比较单纯,无技术债务。

很多情况不是如此幸运的,比如现在有些人遇到的问题,就是发现上下文不是很清晰,这个代码为什么要这么写?为什么一个文件有1万行或者3万行,这个来龙去脉不是很清楚。

这个时候可能就需要从整个子模块来进行一个自上而下的分析。梳理出这个子模块的功能需求是怎样的,需要有多少个公共接口?内部公共接口的实现方式是不是应该像目前这样的?

一个文件能够写成1万行或者3万行,肯定是有一定历史原因的,绝大程度是由于全局把握的编程能力不够造成的。

像这种情况,如果从这个文件本身去做重构的话,难度非常之大,但是如果从上往下,从模块的整个设计角度来做重构的话,可能就容易一些。

对于这样的庞然大物,最好的办法就是分而治之。首先要确定系统的功能逻辑点,针对这些逻辑点,要编排好对应的检测点,也就是说等我们完成了重构以后,我们得确保我们的重构是没有问题的,这些检测点就是做这个的,我们可以理解成集成类的测试。

这些集成类的测试一定要确保可以在当前未重构之前的系统上正常运行。

有了这个设施以后,我们就可以开展我们的重构工作。重构的方法有很多,比如采用比较好的工具,函数和变量的命名改变,调用方式的改变等等。这些是在现有代码的基础上进行的重构。这里我们重点说一下重写的方式来实现重构。所谓重写呢,就是另外开辟一套代码底座。甚至可以选用不同的编程语言。

这种情况下重构首先要重用已有的业务逻辑,实现针对业务逻辑集成测试100%的通过率。

具体不管采用哪种方式都要一个模块一个模块的进行推进。验证完成一个是一个,千万不能急于求成,试图一次性的把某些问题搞定。如果出现很多次失败,有可能会消磨掉你的自信心。所以一定要一点一点的往前推进,始终是在进步当中。采用了这种方式以后,不管当前的系统有多么的庞大,你只要坚持做下去,就一定能够把重构工作彻底完成。

这个时候需要做的具体步骤可以参考如下:

1. 根据功能需求定义公共接口。

2. 根据公共接口写出测试案例代码。

3. 这个时候可以按照测试驱动开发的理念去填充代码。

4. 代码可以从现有的代码中抽取出来。

5. 在抽取的过程中进行整理重构。

这样,这个子模块完成以后,就可以尝试去替代现有的子模块,看看能不能在整个系统中安全的运行。

对于整个系统来说,我们又可以分成很多个子模块。然后又可以对各个子模块各个击破,最终完成对整个系统的重构。

如果一开始对整个系统进行重构的话,也是可以从自上而下的角度来看的。

比如说开始的时候先把所有的子模块看成一些占位符,假定他们已经完成他们的接口了。那对于整个系统来说,它本身就是一个子模块,属于提纲挈领的那个模块。

这个过程,从字面意义上可以理解成重写,实际上,它也是一个重构的过程,因为我们肯定会重用这个系统本身的一些现有代码和现有的逻辑。

上面我们是假定系统在已经完成的情况下进行的重构,其实重构可以贯穿于软件开发的始终。软件开发的首要目标是实现业务逻辑,能够解决客户的问题。这个目标实现以后,我们就要追求代码的干净度,复杂度能够降到最小,当前的技术能够用到最先进。

所以只要有机会,我们都应该对代码和设计进行重构。

质量

质量直接关系到客户是否对我们的产品满意。那我们应该如何保证软件开发的质量呢?

要遵循整个开发团队的共识才能保证质量。共识是一个可大可小的术语,大到理想、哲学、人生观;小到软件设计原则,设计模式,代码风格。如果是打造一个团队那就是长期的目标,共识一定要从大的方向上入手。如果仅仅为了开发一个项目,共识可以从具体的细节着手。

软件质量的保证,需要整个团队形成共识,大家都遵循这个共识。这个共识体现在开发原则,设计模式和代码上,具体表现在架构代码和模板代码上,在项目最初的开发阶段,开发速度一定要慢,就是为了经过反复的推敲夯实,把代码的共识部分建立起来。

风格上的目标是,不管这个团队有多少个人,写出来的代码,就像一个人的代码一样,风格是一致的。

代码的质量也体现在复杂度上。复杂度的目标是,在目前的技术条件下,当前的代码的复杂度应该为最低。

另一个软件高质量的重要指标是代码的白盒可测性。测试的框架应该在项目开始阶段搭起来。等部分代码成型的时候,逐步的添加必要的测试案例。测试案例的选取可以按照环形复杂度的计算方法来确定,也可以根据集成测试对应的用户需求来确定。

接下来进一步细说一下软件开发中的测试。与代码相关的测试,一般有单元测试,集成测试和系统级的测试。

单元测试,一般被认为非常繁琐。单元测试的繁琐主要体现在测试案例的选取上, 如果使用全覆盖方式来选取测试案例的话,会产生大量的测试代码,以后维护起来也是一个负担。如果采用环形复杂度来选取测试案例的话,会产生适量的测试代码,但是环形复杂度的计算也是一个很大的时间开销。

集成测试跟客户的实际业务需求相关。在这个过程中需要理清接口的输入与输出,以及运行路径,然后据此来设计测试案例,写出测试案例代码。

开发人员一般不会拒绝写集成测试。因为她带来的好处是实实在在的,会极大的提高你的开发效率和调试效率。尤其是对于无界面的程序接口尤为重要。

系统级测试是大系统中子系统之间的集成测试。这个主要包含两个方面:

一个方面是有界面的自动化测试,通过这样的测试架构来模拟人类用户的使用过程,同时增加一些随机性的行为,试图能够找出系统的一些漏洞。

另一种是无界面的测试,体现在多个服务系统之间的调用上或者类似浏览器自动化框架的使用上。

一套完整的测试系统,可以帮助工程师提高开发效率,减少以后系统维护和重构的成本。

从测试的紧迫性上来说,集成测试最为必要,系统间的测试有时候使用手工测试通过一些测试工具来代替。单元测试可以有很广阔的讨论空间,这部分要具体问题具体分析。

如果只是为了应付检查而写测试代码,是没有意义的。

如果测试代码没有起到应有的价值,写测试代码也是没有意义的。

工程师是软件高质量的主要执行者。项目组长,架构师和开发经理是软件高质量的护航者和守护者。

所以不能放任让工程师从下而上的去保证软件质量,这个要求对工程师来说过高了。

小结

最后提一下工程师文化和主人翁精神。对于工程师文化的内涵,我认为包含如下几点:

(1)工匠精神,对于所做的事情有着精雕细琢的热忱。

(2)试错文化,勇于尝试,愿意做第一个吃螃蟹的人。

(3)自律,这个自律是指“吾日三省吾身”。不断的自我纠错反省提高。

对于主人翁精神,不管做什么工作,只要想充分发挥自己的能力,真正的做些事情,不管级别如何,薪水多寡,简单地说,就是时刻把所做的事情当作自己的事情来做。否则的话,时刻斤斤计较,我们做事情的时候就无法全力以赴。

如果抱有患得患失的心态,我们的工作效率就会下降。久而久之,不仅赚不到想赚的“大钱”,也会阻碍自己能力和心境的提高,可谓是捡了芝麻,丢了西瓜。时间是宝贵的,真的不容浪费。

对于主人翁精神的一些具体表象很多,诸如:从来不说“这不是我的事”;做事情不为了短期利益而牺牲长期利益;等等。

通过本文,笔者梳理了一下从事软件工作二十多年来的心得体会,希望能给大家带来一些有意义的启示。

以上就是浅谈软件工程师的自我修养的详细内容,更多关于软件工程师的自我修养的资料请关注我们其它相关文章!

(0)

相关推荐

  • 了不起的11个JavaScript代码重构最佳实践小结

    模式和重构之间有着一种与生俱来的关系.从某种角度来看,设计模式的目的就是为许多重构行为提供目标. 1.提炼函数 在JavaScript开发中,我们大部分时间都在与函数打交道,所以我们希望这些函数有着良好的命名,函数体内包含的逻辑清晰明了.如果一个函数过长,不得不加上若干注释才能让这个函数显得易读一些,那这些函数就很有必要进行重构. 如果在函数中有一段代码可以被独立出来,那我们最好把这些代码放进另外一个独立的函数中.这是一种很常见的优化工作,这样做的好处主要有以下几点. 避免出现超大函数. 独立出

  • 浅析Android代码质量管理

    模板方法-基类封装 Activity和Fragment应该是Android最常用的组件,对他进行简单的封装对提高代码的简洁性也有很大的帮助. BaseActivity : public abstract class BaseActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ini

  • PostgreSQL教程(十二):角色和权限管理介绍

    PostgreSQL是通过角色来管理数据库访问权限的,我们可以将一个角色看成是一个数据库用户,或者一组数据库用户.角色可以拥有数据库对象,如表.索引,也可以把这些对象上的权限赋予其它角色,以控制哪些用户对哪些对象拥有哪些权限.     一.数据库角色: 1. 创建角色:   复制代码 代码如下: CREATE ROLE role_name; 2. 删除角色:   复制代码 代码如下: DROP ROLE role_name; 3. 查询角色: 检查系统表pg_role,如:   复制代码 代码如

  • 编写高质量易语言代码注意点

    今天在淘百度的时候看到了这篇文章.觉得很不错.就给亲们分享下. 如果你想学好易语言的话请仔细看看以下的内容吧.看完此文之后保证你大有收获. 什么是一个高效的软件?一个高效的软件不仅应该比实现同样功能的软件运行得更快,还应该消耗更少的系统资源.程序的时间效率是指运行速度,空间效率是指程序占用内存或者外存的状况.另外程序的效率我们也可以分为全局效率和局部效率.全局效率是指站在整个系统的角度上考虑的效率,局部效率是指站在模块或函数角度上考虑的效率. 1. 使用整数和长整数 提高代码运行速度最简单的方法

  • 使用vue3重构拼图游戏的实现示例

    前言 花了两天时间,重构了项目中的一个拼图小游戏(又名数字华容道),为了方便使用抽离成了独立组件,效果如下: 线上体验 源码地址在文章最后哦! 主要重构点 原有拼图游戏是通过开源代码加以改造,使用的是 vue2 .在实际项目使用一切正常,但还是存在以下痛点 源代码臃肿,暴露的配置项不足,特备是和项目现有逻辑结合时体现的更加明显 生成的游戏可能出现无解情况,为了避免无解,只好写死几种情况然后随机生成 源代码是vue2版本,不支持vue3 最后决定使用 vue3 重新实现拼图游戏,着重注意以下细节

  • 重构Python代码的六个实例

    前言 对自己写的冗长代码,想重构但又无思路?小编整理了介绍python代码重构优化的一些方法,助你一臂之力. 编写干净的 Pythonic 代码就是尽可能使其易于理解,但又简洁.所以重构代码让代码简洁易理解是很有必要的. 本文重点是想跟大家探讨为什么这些重构是好想法,而不仅仅是如何做. 1. 合并嵌套的 if 条件 太多的嵌套会使代码难以理解,这在 Python 中尤为如此,因为 Python 没有括号来帮助区隔不同的嵌套级别. 阅读深度嵌套的代码容易让人烦躁,因为你必须理清哪些条件属于哪一级.

  • 12条写出高质量JS代码的方法

    书写出高质量的JS代码不仅让程序员看着舒服,更加能够提高程序的运行速度,以下就是我们的小编整理方法: 一.如何书写可维护性的代码 当出现bug的时候如果你能立马修复它是最好的,此时解决问题的四路在你脑中还是很清晰的.否则,你转移到其他任务或者bug是经过一定的时间才出现的,你忘了那个特定的代码,一段时间后再去查看这些代码就 需要: 1.花时间学习和理解这个问题 2.化时间是了解应该解决的问题代码 还有个问题,特别对于大的项目或是公司,修复bug的这位伙计不是写代码的那个人(且发现bug和修复bu

  • AngularJs基于角色的前端访问控制的实现

    最近做的项目是使用Angular做一个单页应用,但因为用户有不同的角色(管理员.编辑.普通财务人员等),所以需要进行不同角色的访问控制. 因为后端访问控制的经验比较丰富,所以这里只记录了前端访问控制的实现.请注意,前端最多只能做到显示控制!并不能保证安全,所以后端是一定要做访问控制的! 基于角色的访问控制需要做到两个层面的访问控制: 控制页面路由的跳转,没有权限的用户不能跳转到指定url 页面元素的显示控制,没有对应权限的用户不能看到该元素 但在此之前,我们还有一项重要的事要做. 存储用户信息

  • 浅谈软件工程师的自我修养

    概述 "对于知识,要求知若渴:对于自己,要虚怀若谷."优秀的软件工程师一定是在软件开发的道路上前行者.自学是其成长的一个重要手段,在自学的过程中,我们是可以通过考试的方式来收敛思绪,督促自己学习,从而提高自己的基本素质.诚然,原则和模式是软件工程质量的基石.但技术是工具, 是为人服务的,而不是相反的.我们不能为了迎合某种技术而束手束脚,让自己特别难受.与此同时,要让自己的能力发挥到极致,良好的心境是必须要有的,因为软件工程中的一个核心因素是人的因素. 诚然,在软件开发过程中,我们不仅要

  • 浅谈如何降低软件复杂性

    前言 在进行软件开发时,我们常常会追求软件的高可维护性,高可维护性意味着当有新需求来时,系统易扩展:当出现bug时,开发人员易定位.而当我们说一个系统的可维护性太差时,往往指的是该系统太过复杂,导致给系统增加新功能时容易出现bug,而出现bug之后又难以定位. 那么,软件的复杂性又是如何定义的呢? John Ousterhout给出的定义如下: Complexity is anything related to the structure of a software system that ma

  • 浅谈JavaScript编程语言的编码规范

    JavaScript 编程语言作为最流行的客户端脚本语言,早已被众多 Web 开发人员所熟悉.随着 Web2.0 时代的到来和 Ajax 技术的广泛应用,JavaScript 也逐渐吸引着更多的视线.工作中要求越多的是对 JavaScript 语言的深入学习,灵活运用,和对编码质量的保证. 对于熟悉 C/C++ 或 Java 语言的工程师来说,JavaScript 显得灵活,简单易懂,对代码的格式的要求也相对松散.很容易学习,并运用到自己的代码中.也正因为这样,JavaScript 的编码规范也

  • 浅谈C语言中的注释风格小结

    C语言中常用的注释风格有两种,一种是通过如下模式进行一段代码的注释: /* comment*/ 另一种是单行注释符号: // comment 学生时代的注释我一般是选用后者,那时候编码量十分有限,即使是简单的小段落注释使用的IDE也支持批量添加单行注释符.而在编码之中,简单的单行注释进行注释的时候键盘的操作更为简单一点. 不过,工作之后接触了相应的编码规范之后,C语言的注释我基本上放弃了单行注释的方法,最多仅仅在调试的时候做简单的使用. 其实,单行注释是从C++中借鉴来的,算是C++风格的注释方

  • 浅谈Java 中的单元测试

    单元测试编写 Junit 单元测试框架 对于Java语言而言,其单元测试框架,有Junit和TestNG这两种, 下面是一个典型的JUnit测试类的结构 package com.example.demo; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; @DisplayName("售票器类型测试") class DemoTest { // 定义测试的实例 private

  • 浅谈架构模式变迁之从分层架构到微服务架构

    前言 谈到软件系统设计的方法论,在代码层面,有我们熟悉的23种设计模式(design pattern),对应到架构层面,则有所谓的架构模式(architecture pattern).它们分别从微观和宏观的角度指导着我们设计出良好的软件系统,因此,作为一个软件工程师,我们不仅要熟悉设计模式,对常见的架构模式也要熟稔于心.正如看到一个设计模式的名字脑里就能浮现出大致的结构图,当我们看到一个架构模式的名字时,也要马上想到对应的架构图及其基本特点.比如,当谈到分层架构时,我们就应该想起它的架构图是怎样

  • 浅谈如何测试Python代码

    目录 一.介绍 二.测试范围 三.单元测试 四.第一个测试用例 五.异常测试 六.mounttab.py 七.测试覆盖率 八.总结 一.介绍 编写测试检验应用程序所有不同的功能.每一个测试集中在一个关注点上验证结果是不是期望的.定期执行测试确保应用程序按预期的工作.当测试覆盖很大的时候,通过运行测试你就有自信确保修改点和新增点不会影响应用程序. 知识点 单元测试概念 使用 unittest 模块 测试用例的编写 异常测试 测试覆盖率概念 使用 coverage 模块 二.测试范围 如果可能的话,

  • 以Java Web项目为例浅谈前后端分离开发模式

    目录 为什么要前后端分离? 什么是前后端分离? 前后端分离的优缺点? 对于你们的团队和产品有没有必要前后端分离? 为什么要前后端分离? 以Java Web项目为例,在传统的开发模式中,前端代码(Html.js.css)写在JSP中,甚至JSP中嵌入Java代码.当用户访问网站时,页面数据也就是Html文档,由Servlet容器将jsp编译成Servlet,然后将jsp中的html,css,js代码输出到浏览器,这个过程需要经过很多步骤,才能响应用户的请求.这个过程非常繁琐,效率低下,直接造成了页

  • 浅谈Java中Unicode的编码和实现

    Unicode的编码和实现 大概来说,Unicode编码系统可分为编码方式和实现方式两个层次. 编码方式 字符是抽象的最小文本单位.它没有固定的形状(可能是一个字形),而且没有值."A"是一个字符,"€"也是一个字符.字符集是字符的集合.编码字符集是一个字符集,它为每一个字符分配一个唯一数字. Unicode 最初设计是作为一种固定宽度的 16 位字符编码.也就是每个字符占用2个字节.这样理论上一共最多可以表示216(即65536)个字符.上述16位统一码字符构成基

  • 浅谈七种常见的Hadoop和Spark项目案例

    有一句古老的格言是这样说的,如果你向某人提供你的全部支持和金融支持去做一些不同的和创新的事情,他们最终却会做别人正在做的事情.如比较火爆的Hadoop.Spark和Storm,每个人都认为他们正在做一些与这些新的大数据技术相关的事情,但它不需要很长的时间遇到相同的模式.具体的实施可能有所不同,但根据我的经验,它们是最常见的七种项目. 项目一:数据整合 称之为"企业级数据中心"或"数据湖",这个想法是你有不同的数据源,你想对它们进行数据分析.这类项目包括从所有来源获得

随机推荐