推荐 Google API Design Guide

Google API Design Guide

基本上 可以看作是 Google 开放的 API 设计指南。

大体上,Google 对外公开的 API 设计有如下几个特点:

  1. resource oriented design
  2. support both gRPC API and REST API
  3. use protobuf for transcoding

看到第一点的时候还是相当震惊的。

在 Linux 上使用深信服 VPN

因为公司使用 Windows 和 MacOS 的人最多,因此导致两个后果:

  1. 连接公司内网需要使用的深信服 VPN 基本只支持 Windows 和 MacOS
  2. 后端 golang 大仓代码基本只能在 MacOS 或者 Linux 上提交和调试

求一下交集可以发现,在贵司使用 Linux 作为开发平台的同学应该很难过。很不幸的是,我刚好属于那种在 Linux (虚拟机里跑 Mint) 上写后端服务的人。

公司买的深信服的 VPN 服务,那个客户端虽然官方宣称支持 ubuntu,但是事实是压根不能用,连接成功后一旦有数据包就自动断开。

官方论坛有人反映过类似的问题,得到的回答千篇一律都是推荐使用 Windows 和 MacOS。

然而让我使用屎一样的 MacOS 是不可能的;让我在自己的主力台式机的 Windows 上装深信服的客户端也是不可能的。

C++ 工程依赖管理新方向:CMake & Git

本文内容中提及的 CMake 均指提倡 target-based properties 的 modern cmake,而非史前版本的 legacy cmake。

The Right Way: 源码依赖

对于 C++ 工程而言,只要 ABI 的问题还存在,源码依赖就是最稳妥最普适最可靠的依赖引入方式;即使这些引入的源码在构建中会单独编译成(动/静态)库。

同时,GitHub 成为开源文化社区的标杆后,获取实现了某一功能的第三方库的源代码的难度大大降低。

因此个人倾向上:只要允许,都应该以特定版本的源码引入的方式去依赖一个第三方库。

事实上,Google Facebook 这些大厂内部实行的 monorepo 也是源码依赖的一种实现方式,因为某个工程需要的依赖源码都可以一并获取到。

在使用 CMake 作为构建系统的工程体系下,要以源码依赖的方式添加一个子工程只需要使用 add_subdirectory() 添加目标工程的顶层目录(根 CMakeLists.txt 所在的目录)。

Git Submodule: 一次不完美的尝试

我的个人项目 KBase 和 ezio,在此之前都是通过 git submodule 的方式引入自己需要的依赖源代码,然后通过

  • Visual Studio 子工程添加到解决方案(Windows 平台)
  • CMake add_subdirectory() 建联(*nix 平台)

依赖的版本管理直接复用 submodule 提供的特性。

Monthly Read Posts in Jan 2019

Programming Languages

Fun with(out) keyword explicit

The old saying goes: When writing a conversion operator or a constructor that can be called with one argument, make it explicit by default.

By the way, according to comments from the author, the buggy compiler he used was C++ Builder, from Embarcadero, sigh.

Engineering

Simple and Clean Code vs. Performance

  • Performance is not efficiency. // ?? I still can’t get this clear in a programming context.
  • Improve performance after having profiled your system.
  • Make sure use of correct data structures and algorithms
  • By default write code for maintainability.
  • Know and use your libraries, unless your profiler showed them to have bad performance.

Concurrency

Reinventing spinlocks

when implementing spinlock unlock: a simple atomic store is enough. no need for using a heavy CAS operation.

Misc

Testing Memory Allocators: ptmalloc2 vs tcmalloc vs hoard vs jemalloc While Trying to Simulate Real-World Loads

Three pre-requisites:

  • test only new/delete (or malloc/free)
  • use realistic statistic distributions; both for allocated sizes and for lifetime of allocated items
  • access all memory at least once

all for emulating real-world uses.

conclusion:

  • for cpu cycle test, every allocator is not too far from each other. each of them can outperform another one under certain conditions. benchmark is highly recommended when you decide to change your allocator.
  • some allocators behave not so good in memory overhead, like Hoard.

lsof: can’t identify protocol

  • lsof for listing open files; while
  • netstat for displaying network related information, like connections .etc

lsof has issues on locating half-closed sockets.


Linux process states ptrace tutorial part #1

How ptrace relates with linux process states.

using SIGSTOP and SIGCONT to control a process’s state and parent process receives SIGCHLD when child process state changes.

调整 ezio 的 TCPConnection 状态事件

上上周的时候给 ezio 做了一个调整,稍微修改了一下 TCPConnection 对外暴露的几个状态变化的事件。

起因是在写 example/chat-client 的时候,因为主线程单独跑了一个事件循环从 stdin 中读取用户输入,所以 ChatClient 以及内部的 TCPClient 是跑在另外的工作线程上。

因为那个时候 TCPClient 之对外暴露了 connection 和 disconnection 的事件回调(这两个事件还统一成了一个 on_connection()),所以自然选择在 disconnection 的时候进行退出主循环的操作。

但是这个时候会出现:

  • 主循环结束后立马析构 ChatClient,连同内部的 TCPClient 一起销毁。因为这部分代码跑在主线程上,所以不会和工作线程有任何 coordination。
  • TCPClient 会在触发 on_connection() 来表明连接断开后会继续做一些内部清理工作;然而因为前面已经将 TCPClient 析构了,导致 UAF

而当时为了解决这个问题,采用的 workaround 时,ChatClient::OnConnection() 在发现连接断开后,通过 RunTaskAfter() 的方式延后执行 EventLoop::Quit()

这个做法非常丑陋而且不可靠。

来一口 golang 做的玻璃渣

转到后端差不多也快三个月了,拿 golang 糊代码的时间算上自己平时写的一些练手 demo 加起来差不多也有一个月。

这将近一个月的时间过来差不多能体会到 golang 的设计精髓,那就是:simple & stupid, being convenient as the first class support.

换句话说就是:短平快糙猛,满口玻璃渣,怎么方便怎么来。

所以接下来不免俗地是吐槽 golang 设计的内容。

吐槽不考虑 PLT 上的设计,纯粹从日常堆业务逻辑出发。毕竟理论的东西我一个鶸也不懂,且 golang 的设计目的就是方便应届毕业生快速堆业务代码。

以下吐槽点的顺序为自己在实际中遇到的顺序逆序。

Flaky Goroutines

golang 里起一个 goroutine 很方便,但是目前感觉 goroutine 太过于 flaky,有点飘。一旦没用 chan struct{} 或者 sync.WaitGroup ”固定好“,就总有一种这玩意儿是不是已经脱离自己手心的感觉。

另外不知道是不是很多用 golang 的人之前都是 php / python 的背景,相当一部分人其实对 goroutine-safe 没有什么概念。不过严格来说这个不是 golang 自身的问题。

Cannot assign to fields within short declaration notation

代码段

1
2
3
4
5
6
7
8
9
10
11
12
13
func foobar() (bool, error) {
return true, nil
}

func main() {
var err error
ok, err := foobar()
if err != nil {
fmt.Println("error")
} else {
fmt.Println(ok)
}
}

是合法的,因为 ok 之前并没有被定义,所以这里 err 可以蹭着使用 :=