Soul Orbit

I'll take a quiet life. A handshake of carbon monoxide.

这本书很有意思,成书于2014年,豆瓣上现在只有7.2分。很多热评都是在五六年前留的,嘲笑这本书上不切实际的评论铺天盖地。结果呢,去年新冠爆发,科技公司的员工基本全都开始了在家办公,硬生生的把大家狠狠的推了一把!一开始我没做好准备,各种不适应,可是谁也没想到最后的结果却是,效率比在办公室来的更高了,周围的人以前看不出来的各种才华也开始显现了,画画的,跳舞的,甚至出唱片的,百花齐放,而真的有机会见面的时候就更加开心了,一种老友相见的感觉,唠不完的磕~

这个时候再回头看这本书,觉得作者真是先知,每一条都戳在我的痛点上,看完感觉真的学到了不少,于是继续做个笔记,也给大家强烈推荐这本书,别因为豆瓣低分就错过了~

1. 为什么要远程办公?

  • 老式办公方式有很多缺点
    • 办公室中存在大量不受控制的干扰太多,无法专注(这一点我深有体会,有时候我会请假在家专心做事,或者躲在厕所思考解决方案);
    • 通勤浪费大量时间,也浪费地球能源;
  • 远程办公带来了无可比拟的工作自由度,这是属于新时代的奢侈:
    • 没有时间限制:弹性工作制,就算是早起族或者夜猫子也没关系;
    • 没有地域限制:无需挤在大城市,这让生活变得更有趣,想去哪就去哪,不需要等到退休再开始喜欢的人生;避免了办公室成为组织结构中的单点故障(Single Point of Failure,SPoF);远程办公并不一定要去很遥远的地方,只要你喜欢,图书馆,咖啡厅,换什么地方都可以;
    • 这些优点让我们可以不受地域限制的最优秀的人才;虽然远程办公的确能够帮助公司节省开销(场地,员工人数等等),切忌为了节省工资招人异地办公,特别是都没有办法规划重叠时间的员工;
  • 现在机会已经成熟:相关技术已然成熟,远程办公和沟通没有阻碍;远程办公并不是什么陌生的事情,比如外包就是一种,既然能相信外人,为什么不能相信自己招进来的员工呢?
  • 远程办公不必非此即彼:远程工作的本质是,放开手,让你的团队自由,成为它能成为的最棒的样子,不受地域的限制;公司可以保留一些漂亮的办公室,供员工们聚会或者面见客户使用;
Read more »

这本书的作者之一是Ruby on Rails的创始人,David Heinemeier Hansson (DHH),就和书里面说的一样,这本书应该是DHH他们创业之后的副产品 —— 一本讲如何创业的书。虽然如此,但是其不仅仅只对创业有用,对平时的工作也有很帮助。

书里面讨论了创业时心态和方法的方方面面,但我觉得这本书的核心观点归根结底就是作者之一Jason Fried的座右铭:“It’s simple, until you make it complicated.”

1. 给自己卸负

如果你打算创业,那么首先你得为自己卸负。灵感稍纵即逝,有了好的点子,就应该立刻放手去实现,不要为自己找借口。团队小并不是一件坏事,因为它足够灵活,非常适合前期探索和试错。一开始没有投资也不是什么坏事,拉来的投资也就意味着丧失了话语权。另外,行动前,向成功学习成功的经验,而不是失败;

Read more »

In the last post, we discussed the reasons for writing tests, principles and how to write code that is easy to test. In this post, we’ll discuss more on how to write good tests.

First, let me repeat the important thing: Test is a not a silver bullet. Adding a few tests won’t help us improve the code quality that much. If you haven’t read the part 1 yet, it is highly recommended to read it first.


1. Good tests

We are finally here! Let’s talk about writing tests! Making code easy to test is only the first step, and to write good tests we will need some more skills.

1.1. Choose the right way to test

We know that there are various types of tests. And here are some examples:

  • Unit test: Test a class or a small module by talking to them directly, e.g. calling public member functions.
  • Module/Service test: Test a module or service by simulating its upstream and downstream services.
  • End-To-End test (E2E test): Test a complete system by simulating the upstream and downstream services of the whole system.
  • Integration test: Integrate all services, even multiple systems, as required and test them.
  • In-Service/Probe test: Test the services within the service itself or with a dedicated probe service at regular intervals.
Read more »

“Please write a UT for this change.” is one of the most frequent comments I leave in the code review. And I am seeing people tend to write minimum tests just for having something to pass the review.

Well, I kind of understand writing tests is annoying sometimes, but tests are extremely helpful and there are things could help us writing them too. So let’s talk about test!


1. “Writing test is so annoying”

“Hey! It compiles! Ship it!”

When talking about writing tests, many people find it annoying for simliar reasons:

  • Extra work. Most of time, writing tests is very time consuming. And sometimes, it will take even longer time than development itself.
  • The thrill of developing a new feature is usually over after the core logic is done.
  • Writing test is a tedious work. And you might not even be able to find a single bug after writing tons of tests.
  • We have added a lot of tests for a feature. Then the feature changed, and all the tests have to be rewritten, which greatly slows down the development.

All these questions and complaints are basically because we don’t understand the real intention of testing, and finally fall into the misunderstanding of writing test for the sake of writing tests. And when we are forced to do something, we are never going to feel it will benefit us, even if it really does.

Read more »

上篇中,我们主要讨论了写测试的理由,原则和如何写出易于测试的代码。这一篇里,我们会来真正讨论如何写出好的测试。

这里重要的事情再重复一遍:测试不是一剂万能药,加几个测试并不能帮我们改善多少代码质量,把代码本身写好才是根本。如果还没有读过上篇,这里强烈推荐先阅读上篇


1. 好的测试

现在,我们终于可以开始写测试了!好的代码只是我们实现好测试的第一步,要写出好的测试我们还需要更多的一些技巧:

1.1. 选择合理的测试

我们知道测试的类型多种多样,有且不限于如下一些类型:

  • 单元测试:通过调用一些特定的函数(比如公开的成员函数)来测试一个类或者一个小的模块是否工作正常
  • 模块/服务测试:通过模拟一个模块或服务的上游服务和下游服务来测试它是否工作正常
  • 端到端测试(End-To-End Test / E2E Test):通过模拟整个系统的上下游服务来测试这个完整的系统是否工作正常
  • 集成测试:将所有服务,甚至多个系统,按照要求组装起来,进行测试
  • 在线测试或探针测试:服务内部定时使用API对其服务状态进行测试
Read more »

最近在做一个多团队合作的项目,需要将我们的服务的配置管理和自动化部署流水线从一个平台迁移到另外一个平台,但是这个项目很要命的是,另外一个团队的成员一心只想赶快完成任务,代码的改动从来就不加测试,每次做了两行修改就开始在自己的分支上创建Official build,然后上运营环境测试。劝了好几次也无动于衷,总觉得测试是一件麻烦的事情,拖了他们的后腿。其实这个项目本来并不复杂,偏偏他们做了两年都没做出来,还弄出不少线上事故,真的是事百倍功半,所以这次就想单独写一点关于测试的事情。


1. “写测试真的好烦”

“Hey! It compiles! Ship it!”

每次提到写测试,很多人会觉得很烦,原因都大同小异:

  • 额外的工作,而且大部分时候极度耗时,甚至比开发的时间还多
  • 开发新功能带来的快感很多时候在功能相关的代码写完之后就结束了
  • 写测试总感觉是个体力活,写了一堆也不一定能发现一个问题
  • 为某个功能写了一堆测试,然后功能变了,所有的测试都要重新写,拖慢开发速度

有上面这些疑问和抱怨,基本上都是因为没弄明白测试的真实意图,最后陷入了为了测试而测试的误区。而当我们被迫做一个事情的时候,我们是永远都不会觉得做这个事情有什么好处的,即便它真的有。

Read more »

最近在一次分布式系统的线上交流中,发现居然有那么多种不同的一致性模型,而且因为种类太多,大家理解上也有很多不同,看了一些资料,虽然很多讲的很好,但是过于复杂或者书面,难以理解,所以在这里尝试着为每一个模型做一句话总结,希望可以帮助大家理解。如果我的理解有误,也请大家指正~


1. 啥?啥一致性?

一致性虽然是我们非常常用的一个词,但是非常不幸的是,这个词有太多的含义,在使用的非常容易混淆。所以在讨论一致性之前,我们需要先来看一下一致性的定义:

首先是我们常说的Consistency。这个词经常在两个地方出现:分布式系统的CAP和数据库的ACID。虽然其中“C”都叫一致性(Consistency),但是其含义却截然不同:

  • ACID中的一致性:这里主要说的是一种数据上的约束,比如主键是否唯一,或者外键关系是否保持等等
  • CAP中的一致性:这里主要说的是不同节点之间数据的同步状态,是不是能让客户端请求处理看上去像访问一个单体系统(Monolith)一样。

然后是Coherence。这个词虽然也翻译成一致性,但是它和上面的一致性截然不同。Coherence指的是多实体或者多层级的数据之间是否一致,比如:缓存一致性(Cache Coherence,缓存中的内容是否和原始内容保持一致)。而Consistency指的是一个单实体本身是否一致,比如上面提到的同一个数据库里的外键关系或者同一个服务不同节点之间的同步状态。

Read more »

好了,在简单探索完基础类型之后,我们就来看一下我们最关心的Struct吧!


1. 简单结构体

我们先从最简单的开始,先定义一个简单的结构体,里面错落的放一些大小不一的字段:

1
2
3
4
5
6
7
8
type A struct {
FA1 bool
FA2 int32
FA3 int16
FA4 int64
FA5 byte
FA6 byte
}

然后定义一个变量a,再用上篇文章中的DumpObject函数来看一下其内存布局:

1
2
3
4
5
6
7
8
Var         Type           Address             RootOffset LocalOffset Size
a objmodelexp.A 0x000000c00000e520 0 0 32
a.FA1 bool 0x000000c00000e520 0 0 1
a.FA2 int32 0x000000c00000e524 4 4 4
a.FA3 int16 0x000000c00000e528 8 8 2
a.FA4 int64 0x000000c00000e530 16 16 8
a.FA5 uint8 0x000000c00000e538 24 24 1
a.FA6 uint8 0x000000c0001121f9 25 25 1
Read more »

也许是从C++转过来的习惯,学习一门语言,我总是比较喜欢先弄明白它的对象模型,所以自己就做了一些简单的实验,看看Go的对象模型~


1. 前置准备

为了查看对象的内存布局,我们这里先写一个非常简单的小函数,利用反射递归地遍历对象的所有成员,然后输出其内存位置,从而了解其在内存中的真实状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func PrintObjectDumpTableHeader() {
fmt.Printf("%-12s%-15s%-20s%-10s %-11s %-4s\n", "Var", "Type", "Address", "RootOffset", "LocalOffset", "Size")
}

func DumpObject(name string, p reflect.Value) {
v := p.Elem()
dumpObject(name, v, v.UnsafeAddr(), v.UnsafeAddr())
}

func dumpObject(path string, v reflect.Value, rootBaseAddr uintptr, localBaseAddr uintptr) {
dumpObjectDetail(path, v, rootBaseAddr, localBaseAddr)

switch v.Kind() {
case reflect.Struct:
childLocalBaseAddr := v.UnsafeAddr()

for i := 0; i < v.NumField(); i++ {
fieldPath := fmt.Sprintf("%s.%s", path, v.Type().Field(i).Name)
dumpObject(fieldPath, v.Field(i), rootBaseAddr, childLocalBaseAddr)
}
}
}

func dumpObjectDetail(path string, v reflect.Value, rootBaseAddr uintptr, localBaseAddr uintptr) {
fmt.Printf("%-12s%-15s0x%016x %10v %11v %4v\n", path, v.Type().String(), v.UnsafeAddr(),
v.UnsafeAddr() - rootBaseAddr, v.UnsafeAddr() - localBaseAddr, v.Type().Size())
}

这样,我们就可以非常简单的调用这个函数来查看任何对象的内存布局了,如下:

1
2
3
4
PrintObjectDumpTableHeader()

var b bool
DumpObject("b", reflect.ValueOf(&b))
Read more »

最近难得放假,想好好学习一下Go,毕竟C++用的我欲仙欲死,而平时比较常用的.NetCore也不是编译语言(Compiled Language),经常遇到一些神奇的限制……

学一门新语言说容易也容易,毕竟语法也就那么一些,而且Go非常精简,只有仅仅25个保留字,但是说难也难,要真正理解一门语言真的需要花费不少的心思,特别我属于那种不了解到一定程度连用都不敢用的人(在工作中经常因为需要使用一些库,就把这些库的实现通读一遍……),于是查找了不少的学习资料。我觉得这些资料对于新手上路真的非常有用,所以把他们都记录在这,希望也会对其他对Go感兴趣的朋友有所帮助。

那就让我们开始吧!
Gopher

1. 基础入门

首先,我们先从最基础的开始:

  • 弄明白怎么使用是第一步,官方的示例讲解必不可少:A Tour of Go
  • 接下来,可以系统的看看Go语言的方方面面,Go语言圣经gopl当仁不让:gopl.io,而且还有中文版
  • 在了解了Go语言本身之后,我们还可以看看语言的一些最佳实践,官方的Effective Go绝对值得一读:https://golang.org/doc/effective_go.html

至此,基础入门肯定是没有问题了,但是如果你是从C/C++这种比较传统的编译语言转过来的,估计到这里会一头雾水 —— 语法我都懂了,但是为什么呢?比如,为什么Go的struct成员变量和函数不提供const修饰?为什么没有信号量?使用嵌入代替继承看着很好,但是多态用起来经常却经常踩坑?这些问题我们就需要更多的资料来帮忙了。

Read more »
0%