start from a building a list

事情的开始总是有个目标,目标拆解下来总是一个任务列表,列表是关键,想办法把列表做出来,然后再想办法丰富这个列表,或者曾长/缩短这个列表

示例

  • 静态检查的lint工具(rubocop/golangci-lint…),通过检查代码,汇报violation,这是violation的列表
  • sonarcloud检查代码质量,测试覆盖率,以文件列表的形式展示结果,这是分析结果的列表
  • 一项业务流程由一组事件构成,这是一个事件的列表
  • 要检查业务系统里的开关哪些是可以清理的,需要建立一个业务开关的列表,为它们添加元信息,例如创建时间,默认值,当前值,更新时间… 这是一个包含元信息的开关的列表
  • 要分析生产变更和生产事故的之间的关系,需要建立生产变更和时间相关的列表(log),逐渐为每个变更添加元信息,聚合分析这个log,更通用一点的抽象是将生产变更/生产事故…等一切与组织/系统相关的改动都视为”事件”,然后来分析这个事件的log,可以得到很多有价值的信息。这里的核心还是个列表,事件的列表(元信息包含时间戳)
  • 数据结构中的”graph”也是很好的例子,数据结构的表示可以用一组边(edge)来表示,这里还是一个列表,单独看每条边和每个节点都是很无聊的,用图的算法来分析具体问题才是有趣的地方!这里的核心还是列表,在记录时只关心两个节点之间的关系,而暂时不关系整张图的样子,最终的分析结果和可视化结果更加有意义
  • 用列表的思路来处理问题时有两种思路,做出列表,然后把列表变短 — 适用于分解问题,分离关注点;或者做出列表,然后把列表变长 — 适用于框架,逐步优化,逐步深入。<— 没想清楚,需要再深入一点

what must be clear while upgrading application/dependencies?

Given

  • new version is compatiable with old version
  • old version is NOT compatiable with new version

Then

  • rollout(old -> new) or rollback(new -> old)
    • case#1 new produce -> new consume OK
    • case#2 new produce -> old consume ERROR
    • case#3 old produce -> new consume OK
    • case#4 old produce -> old consume OK

Review

  1. if retry could make case#2 work, then it’s ok and expected, otherwise we need to figure out how to do the upgrade carefully
  2. if cache object deserilization is included, better consider using a fresh new cache key(sth like version number) to make sure new version won’t load the outdated version of cache data

Continuous Conscious Self-Improvement

Blog content copied from Continuous Conscious Self-Improvement | zenspider.com | by ryan davis

  • How do you develop software?
  • Is it effective? (and how do you know that?)
  • Are you focusing on improving yourself?
  • Where are you at? Where do you want to be?
  • Could you do better?
  • Where could you put the least amount of effort to improve the worst?
  • When do you do that?
  • What would your teammates answer (about you)?
  • What can you learn from them?
  • What are you doing to get there?

Incident Review

今天因为我的失误导致了一次小故障,持续大概一小时才被发现,影响10多个用户,需要修几十条数据(粗略估计)

这是在公司因为我导致的第二次问题,有必要把反思记录一下

第1次问题(2022年底)

功能开发完成,QA内部测试完成,但是隔了有一段时间才真正在生产环境启用,导致功能开关的影响范围没有完全理清,和另一个功能开关的开启产生了干涉,问题持续了近10个小时才被发现,导致有几千条数据异常;最后只得花了很多精力从日志里捞数据,修数据,非常麻烦

当时反思有这几点原因:

  1. 功能内测结束后没有重置功能开关
  2. 打开功能开关之前没有检查功能开关的状态,没有考虑到功能之间可能产生干涉
  3. 一段时间内,同时在处理的事情有点多了(WIP数量有点多),精力太过分散,review不到位
  4. 对生产环境变更缺少敬畏心

第2次问题(2023-04-12)

有一个较大的任务,是给多个业务场景添加source_typesource_id, 以便于数据查询和统计;最近到了收尾阶段,有几个场景的改动在其他团队阻塞了近1个月,为了不完全被阻塞,leader和我先把后续的验证环节先做好了,准备内测

今天刚刚开启内测的开关,因为考虑不周,导致了空指针异常

直接原因是遗漏的几个场景没有部署,导致对应的source_typesource_id为空

根本原因是自己的疏忽,有这么几点

  1. 测试用例里,应该捕获到这个问题,但是实际上没有,这是偷懒导致的
  2. 在有几个场景被阻塞的前提下,为了不完全被阻塞,开始做其他的事前,没有想清楚哪些事是需要注意的,多想一步,就可以想得到之后的测试用例要着重关注它们
  3. 修改不熟悉的代码时,不够细心,最基本的为空的情况被自己遗漏了
  4. “后续的验证环节”这部分代码,不应该影响业务流程,这里最保险的方法是加上异常捕获(fail-safe);虽然捕获一个general的异常是糟糕的实践,但在这个场景下其实是很合适的,我因为心底拒绝这种实践,所以完全忽略了这种做法
  5. 开启开关后,对生产环境的监控疏忽了,竟然是近1个小时后才从告警群里发现有问题…
  6. 对生产环境变更缺少敬畏心

反思

  1. 无论业务是否关键,变更前都要想清楚怎么监控,怎么减少错误出现的可能;如果一定不能出错,fail-safe的做法就是必要的
  2. 对生产环境变更要有敬畏之心
  3. limit WIP, 把事情做好,不要一下给很多事开头,不停的在很多事之间切换
  4. 常识: 多想想如果为空会怎么样; 自信想了一下,没考虑到这个,和写代码的方式也有关,方法定义的方法调用的地方相隔太远,没有有意识的去专门检查,如果他们离得近,发现他们的概率会提升很多
  5. 如果想不清楚,就先不要开启,就先不要发布;和生产环境相关的变更,头脑不清楚的时候不要动
  6. 这两次问题影响范围不算太大,算是教训;如果不注意,以后犯更大错误的可能性更高;一定要多培养好习惯,发现和克服坏习惯

My understanding for IoC(Inversion of Control)

20230322 free chat sharing notes

Framework vs Library

  • our code calls library code
  • our code called by framework code

My understanding for IoC

IoC is we as programmers write codes that are called by Frameworks

  • control structures: Sequence, Selection & Iteration
  • normally we write business logic as step1, step2, step3… using above control structures
  • but we will notice bolier templates as we getting more and more familar with them, for examples:
    • we always need to close an open file
    • we always need to declare an empty array if we’re only interested in part of the elements in a list
    • some code only differs in the middle part

Examples

  • map/filter/reduce(pipelined list handling)
    • list.filter {}.map {}
    • list.filter {}.map {}.reduce {}
  • ruby: partition/all?/any?/none?
    • (1..6).partition { |v| v.even? } #=> [[2, 4, 6], [1, 3, 5]]
  • dsl(describe what to do, not how to do it)
  • framework
    • rails
    • event_sourcing
  • lambda(ruby block / First-class Function)

Take aways

  • find & use good abstraction(e.g.: use map/filter/reduce more)
  • learn more about the framework we’re using

References

Some common sense

最近这些简单的感悟和常识经常在脑袋里窜, 记下来供以后review

  1. 没有人阻止我去重看那些以前看不懂的东西(文章/书/电影/知识点…), 多看几次, 随着知识增长, 大概率会慢慢看懂并且学会的
  2. 没有人阻止我去练习那些不容易掌握的能力和技巧, 难是正常的, 刚开始不会也是正常的, 硕哥以前教过我: “我不会是因为我欠练”, 多多练习, 一定能提升熟练度, 慢慢掌握的
  3. 没有人阻止我做很多我认为正确的/有价值的事, 唯一的阻碍就是自己想偷懒, 问题在自己
  4. 守好自己的钱包, 在接受别人分享的”赚钱机会”时, 想想你是不是他爹? 凭什么他不自己闷声发财
  5. 重要的信息一定要确认来源, 多方验证, 要重视”验证码”的重要性
  6. 要多积累常识, 多思考”老生常谈”的含义, 做决定时多调用常识, 多多沟通
  7. 人给自己找理由实在太容易了, 不要怕麻烦, 如果自己思考不清楚, 应该向更厉害的人求助; 行动起来就会遇到问题, 遇到问题就解决问题, 坐在那里给自己找理由实在太容易了(还没做到…)
  8. 多想想怎么能把自己在做的事的价值描述清楚, 如果想不清楚, 说不清楚, 是不是说明在做的事没价值? 如果不是, 为什么说不清楚? 有什么是自己不敢面对的么?

review and remove unused gems

review and remove unused gems

1
2
3
4
5
6
7
bundle list --without-group dev development staging test
bundle list --only-group default production

tldr du
tldr sort

for dir in $(bundle list --only-group default production --paths); do du -shk $dir ; done | sort -nr

Abstract Data Type Collection

“和任何编程概念一样,理解抽象数据类型的威力和用法的最好办法是仔细研究更多的例子和实现” — algs4 ch1.2

  • Counter
  • Interval1D
  • Interval2D
  • Date
  • Transaction
    • from_user
    • to_user
    • created_at
    • amount
    • currency
    • souce_id
    • source_type
  • List
  • Stack
  • Queue
  • Bag
  • Tree

ref: Reading 10: Abstract Data Types

昨天复习优先队列的时候,才真正注意到 ADT 和 data structure 是两个不同的概念

比如优先队列(priority queue)是一种ADT, 所以他的实现可以有多种, 基于数组实现的而叉堆只是实现它的一种数据结构

比如栈(stack)是一种ADT, 基于数组实现的栈是一种数据结构, 基于链表实现的栈也是一种数据结构

(还是不够清晰,甚至感觉有错误…)

Find unused local variables in ruby project

Inspired by SublimeLinter plugin for ruby, using ruby -wc

1
parallel "ruby -wc {}" ::: $(find . -name \*.rb) 1> /dev/null

Known issue

it only detects local variables for “warning: assigned but unused variable - xxx”

not working for instance variables

probably work with unused-code/unused to detect other unused tokens

unused

1
2
3
4
5
6
7
8
# https://github.com/universal-ctags/homebrew-universal-ctags
brew install --HEAD universal-ctags/universal-ctags/universal-ctags
brew install unused --with-mimalloc

alias ctags='/usr/local/bin/ctags'

# go to project working dir
ctags --recurse . && ls -lh tags && unused