💼 从工作中学到的

    💼 从工作中学到的

    最近的两个需求尝试以 “面向测试开发”来开发。所谓“面向测试开发”,或者“测试驱动开发”,我理解就是先去写UT,先去在UT里面写好调用的函数和预期的接口。每写一个EXPECT,对应去实现类的功能,这样写完UT,功能也开发完成了,保证了模块的质量。

    通过这种方式发现写代码的阻力更小一些。之前写代码脑子里可能混杂多个接口的设计想法,通过UT,每次只增加一个新的case,实现该case,能够“小步快走”,会更不容易出错。

    这对项目代码质量是有比较大的要求的,如果是一个新的独立模块,还好一些,可以从零开始写UT,如果这个模块有依赖外部模块,需要mock或者外部模块也具有可测性。

    如果是在已有的功能模块里新增新的功能,这就要求已有模块可测性非常强才行。历史的很多代码都没有UT,这也是困难之一吧。

    💼 从工作中学到的

    “当你排除一切不可能的情况,剩下的,不管多难以置信,那都是事实。”

    工作中排查bug的时候很像是侦探🕵️寻找真相。简单的bug可能很快从代码review就能发现,比如空指针等。这周遇到了一个bug ,简单来说,

    • 正常情况下是先执行B操作,再执行 C操作。
    • 执行A 操作后,预期就不可能有B操作或者C操作了,但是A操作它是跨线程异步过程(一般时间很短几毫秒或者几十毫秒之内)。

    线上的问题是在A操作过程中,出现了B操作,导致后续C操作的时候直接崩溃。所以线上会有概率非常小的情况下崩溃。

    这里写代码的时候没有考虑到这个异步过程,同时B操作或者C操作中应该增加判断,如果A操作后,就是空操作。

    💼 从工作中学到的 对于客户端开发来说,crash是性能/稳定性中最重要的指标之一,因为crash意味着功能不可用。

    最近工作上引入了两个功能crash,被折腾了一番,有一个感想:“对任何改动的上线一定要测试”。这里“测试”根据不同情况有不同程度测试,其中最基本的测试是确认功能是否能跑起来,而不仅仅是编译通过即可。

    可能你会说,提代码肯定需要测试啊。但是有些场景,可能就会偷懒,比如加一行日志,或者简单增加一个指针判空,或者简单调整了两行代码的位置,就因为“匆忙”,并且过度自信,就没有测试,甚至基本测试都没有!

    上述的场景可能是本地的分支开发别的功能,突然反馈过来的一个bugfix,为了本地不切分支,而选择在网页端简单提交bugfix的代码

    这些看上去“人畜无害”的代码,其实往往暗藏“玄机”。比如日志打印调用了一个指针的函数,却没有检查指针是否为空,误以为指针一定不为空,尤其是在编写宏的情况,更容易忽视。

    除了这些改动极小的代码,一些不是特别大的改动也可能引入意想不到的问题。举个例子,移动了某一个observer 事件发送的位置,在模块owner看来可能没什么关系,但可能外部利用了这个observer,并且依赖了某种时序,一旦某两行代码调整了顺序就可能导致异常。

    这里有一个调整两行代码顺序导致问题的例子:

    ....
    std::string str = "1234";
    SomeStrToInt(str);
    SomeClassConstruct class (std::move(str));

    其中第3行和第4行的位置调整就会导致异常,而这个问题非常难以发现,因为最开始的这段代码可能比较久远,甚至不是自己写的,因此就会忽视后面对string move的调用。


    有经验的程序员是否可以避免上述问题,足够细心的条件下一些简单的错误可以被避免,比如上面的std::move 顺序问题。但是对于更复杂的场景忽略掉也是可以被理解的,更不用说,粗心是一种很容易犯的问题

    因此黑盒测试的必要性是无法被白盒测试替代,白盒测试100%覆盖是一个理想而不及的目标,受限于代码可测性、ut质量等等因素。意味着一定有不少场景是UT无法覆盖的部分,对于大型项目尤其如此。(尽管如此,UT重要性仍然是不言而喻)


    我个人的一点想法是对任何提交MR做以下两点检查:

    • 做了哪些测试来减少问题发生 (至少要测试功能是否可以跑起来,而不是过度自信)
    • 是否对该处改动的所有外部依赖都清楚,如果不清楚则优先考虑使用灰度验证的方式上线(比如修改某个对外的接口返回值,不要过度自信!)

    上面的两点check不能避免所有的问题,但可以拦截大部分很低级的问题(事实很问题都来自低级的错误),除此之外,成熟的工程会一般会有完备的稳定性流程来拦截更复杂的问题。

    💼 从工作中学到的 下班后如非必要,最好是不要打开与工作相关的任何网站、软件。只是简单的看看消息也会很快的让人感觉到“班味”。这对于放松心情是非常有害的,同时也不利于第二天更有精神的工作,长此以往会导致越来越强的厌倦。

    字节中有「字节圈」,类似内网的“微博”程序。之前很长一段时间会经常的刷,虽然这些内容都是素不相识,但也是打发时间了,不仅如此我还会频繁的去看飞书上一些免打扰群的消息,即使那些消息和我并没什么关系。后来我发现这种状态是非常有害的。即,我已经下班了,但是我的状态并没有完全下班,是祈求用忙碌、麻木的工作错觉来填补自己无事可做而已。这就是为什么上述说的如非必要,一定不要查看任何与工作相关的任何信息。

    平均来说,越少的工作时间确实是可以有更好的效率的。尝试了一段时间强制自己更早下班,会发现为了要更早下班,自己会强迫自己提高效率完成今天的事情。就好似是一种dealline。(当然特殊情况除外,但要尽量的少)。

    所以,如果一个公司强制员工更早的下班,同时以工作成果为绩效导向,我觉得是会让员工自发的寻找效率更高的方式的。

    此条为私密说说,仅发布者可见

    💼 从工作中学到的 职场中应该会有很多时候会受到挑战。比如工作流程(开发/需求流程等等)是否合规,技术方案是否合理,考虑全面,代码是否严谨等。要学会受到挑战的时候不要急的把自己择出去,这样的心态会让自己会急躁的为自己辩解。但事实上很多时候不需要辩解,只需要解释,所以要缓一缓,如果是通讯工具沟通,不要急于回复,理清思路再回。面对面沟通,也可以停顿、思考片刻后给出回答,切勿自乱阵脚,有理也说不清。

    📝 每日记录 今天北京下大雪了,这可真算得上是鹅毛大雪!下班的时候,走在路上,雪特别的厚,踩在上面还有咯吱咯吱的声音,非常治愈

    补充一则记录:春节前,第一次点这家的烤串,点了一个烤猪蹄,特别好吃,送过来的时候温度也不错,猪蹄也挺嫩的。复工回来的时候,又点了一次烤串,发现很一般了。相似的经历是之前的一家炸鸡店,第一次点手枪腿,真的是太好吃了,手枪腿里还有汁水,第二次点怎么这么一般。不太清楚是丧失了新鲜感,还是确实餐品质变差了!

    PS:已经高强度上班三天了!
    PSS:明早还要早起赶文档!!

    此条为私密说说,仅发布者可见

    📝 每日记录 从4月末开始,每天熬夜到1点半,身体每况愈下,以至于再也不能不重视了。

    身边新冠第二波的人也变多了。倒是一直没有发烧过,因此也不知道自己有没有阳过,不过其他的症状从1月放开后持续不断。 腰痛、咽喉不舒服,胸闷,呼吸不畅,口腔溃疡等等几乎不间断轮番上阵。

    这半个月来,从新需求启动忙到焦头烂额。但是身体永远是第一位,所以下班后不再想任何工作的事情了。

    💼 从工作中学到的 关于工作,从0启动了一个需求,所以涉及到大量的方案设计与评审的工作。在这里体会最深的一点是:过度设计是一切的根源。很多优秀的技术架构是需要演变的,而不是一步到位。

    在代码设计中,有很多不错的设计模式和设计原则,以便代码便于扩展,容易测试。但是在实际的设计中,很容易从一个具体的需求想要设计一种“极其通用”的设计方式。模块越通用带来的复杂度就越高,因为需要兼顾更多的场景。

    所以不如变成两个模块来做,而不是想要一个模块非常灵活、通用的完成所有需求。

    尤其是在刚刚接触一些设计原则的时候,我们想要在代码的所有地方去应用,比如单一职责,开闭原则、MVC等等。可能会让一个没有那么复杂的需求拆分成很多独立的模块,导致这些模块之间需要还需要通信,或者函数需要不断的通过层级来偷传,这无疑增加了复杂度。

    当然好的代码需要一定的设计,这其中的权衡是需要在不断的实践中掌握的。

    💼 从工作中学到的 「输出论据比论点更有价值」最近在写绩效评价相关的,有一个感受就是情绪或者主观评价都是比较虚的。所以才会有所谓的「夸夸宝典」,这些主观评价就像是一个结论或是论点,必须需要有论据支撑才有价值。当然这个场景下论据与论点结合更适合。

    这个观点同样适用于其他的事情上。比如与别人沟通上,即使你要和别人吵架,提出你的不满,你可以数落对方做的不好的地方,让你烦、讨厌的事情,但最好减少去输出主观的评价或情绪。比如直接人身攻击,大骂对方没素质等等。输出论据,大家也能心知肚明知道你的不满了。而情绪和观点是可能会变的,过几天你可能会因为一时冲动输出太多情绪而后悔,但是事实是不会变的,这不会让自己觉得“冲动了”。

    💼 从工作中学到的 写文档和设计代码有一些相似之处。一个比较复杂的话题想要展开,就好比设计一个复杂功能的类。全部代码写在一个文件中当然可以,就会导致单文件代码行数太多,阅读起来很费劲。如果我们能更好的封装与模块化代码,单个类的功能就会更清晰。

    同理,写一篇复杂话题的文章,也可以有类设计的思想,先介绍最基础的部分,然后基于这个基础会有多个分支展开(子类继承)。多篇文章之间环环相扣,而每篇文章也不会太长,阅读压力也不大。

    我也看到过有很长文章从头到尾讲一个复杂话题的,写的也特别的好,这个就好比仍然是多个类,只不过放到同一个文件里面而已。

    此条为私密说说,仅发布者可见

    💼 从工作中学到的 当我们CR代码的时候,我们在review什么。 其实很难和代码作者本身理解程度来review代码逻辑的正确性,而是应该review一些常见的代码写法的问题。比如指针是否有空指针风险,函数本身的设计(如输入参数在输出参数前面)等等代码规范的问题。

    除此之外,如果对代码需求的细节了解更多,可以review 一些代码的逻辑,比如改动代码是否会影响之前的调用流程。

    CR中几乎做不到的是判断每个变量计算的值是否符合预期,这个需要代码作者本身来保证。

    正常来说,别人给你CR的意见都是你自己每次自己CR的时候应该发现的,所以提高代码质量的一个好方法就是记下每次别人给自己的评论,并反思为什么自己在检查代码的时候没有发现(还是自己并没有检查代码)?

    📝 每日记录 工作如果获取不到持续的成就感和进步,是很容易陷入一种痛苦、迷茫、虚无的感受的。尤其是如果一直工作没办法按照排期完成,一直后延、后延、后延,只是无尽的麻烦... 💼 从工作中学到的

    💼 从工作中学到的 因为国庆大部分时间都在忙工作,节后的几天又继续加班到挺晚才回来,快晚上十点回来后,因为天气变冷,挑选一些过冬东西,然后就已经到凌晨了。这种连轴转到今天早上的时候,闹钟都叫不醒我。整个人特别的困,与此同时也会让我面对环境更加敏感脆弱。所以,过大的压力、不好的作息这些会更让人容易emo,陷入不好的情绪当中。

    今天晚上吃完晚饭就回来了,调节一下。工作的本质,不是为了ld工作,而是给自己工作,提高自己的技能,能挣钱才是目标。不要让自己陷入无尽的社交困境里面,找准靶心,调整节奏,健康作息。

    最近快入冬,身边感冒越来越多,流感也来了,永远是只有身体不舒服的时候才知道健康多重要,

    💼 从工作中学到的 💻 代码思考在正式工作之前,我没有写过单测,主要是平时自己写的代码通常耦合度较高,没有单独抽象设计模块的概念。

    最近开始写一些通用能力的基础库需要写单测。第一次单测的编写是在代码基本完成后开始写的,完成单测后会发现一些bug,于是修改bug。但这个过程中会发现代码设计的一些不合理之处,比如多个接口的返回值是否更统一,对于接口可能出现错误时的返回值,应该如何处理(这个可以多参考chromium base库中的代码实现)。如果一个模块的多个接口设计不统一、那么单测同样也会非常复杂。

    其实上面的过程就有点TDD那味了,但是测试驱动开发,需要先写一个无法通过的测试,通过修改代码来使得测试通过,再重构代码。在这个过程中不断的开发代码,而不是先写完代码,再写单测试。

    单测的重要性是毋庸置疑,因为代码复杂性总可能出现某个分支逻辑错误。因此TDD将单测与开发结合,减轻了写单测的难度和压力,同时也能通过单测进一步发现代码的设计问题。

    参考文章:

联系方式

关于我

  • 来自南部的一个小城市,个性不张扬,讨厌随波逐流。

那年今日

👍

此条为私密说说,仅发布者可见

📝 每日记录 这个周末做的事情还是相对较多的… 周六,本科室友小聚一下,因为其中一个室友要离京回老家工作了。算下来他在北京工作也有4年了。吃了顿饭,去了KTV。商场的人非常之多,而我已经大概6...

“它不能以愉快和不愉快而论,我只想生活得强烈一些”

早上做梦,梦到自己提交的代码又出现编译问题了,被别人找,吓醒

📝 每日记录 这一周居家办公,感觉时间比平时更快了一点。而且活动量几乎就是下楼取外卖。小区从上周末被封到今天下午才解封。没有解封的时候,每一餐外卖都要去小区大门口去取。而且避免被别人拿走,点完外...