#783 Golang 版本

2022-04-10

2007 Robert Griesemer、Rob Pike 和 Ken Thompson 三位巨头都在谷歌任职,开始设计一门全新的语言。

Release Status Release date Maintenance end
go1 End-of-Life 2012-03-28 2013-12-01
go1.1 End-of-Life 2013-05-13 2014-06-18
go1.2 End-of-Life 2013-12-01 2014-12-10
go1.3 End-of-Life 2014-06-18 2015-08-19
go1.4 End-of-Life 2014-12-10 2016-02-17
go1.5 End-of-Life 2015-08-19 2016-08-15
go1.6 End-of-Life 2016-02-17 2017-02-16
go1.7 End-of-Life 2016-08-15 2017-08-24
go1.8 End-of-Life 2017-02-16 2018-02-16
go1.9 End-of-Life 2017-08-24 2018-08-24
go1.10 End-of-Life 2018-02-16 2019-02-25
go1.11 End-of-Life 2018-08-24 2019-09-03
go1.12 End-of-Life 2019-02-25 2020-02-25
go1.13 End-of-Life 2019-09-03 2020-08-11
go1.14 End-of-Life 2020-02-25 2021-02-16
go1.15 End-of-Life 2020-08-11 2021-08-16
go1.16 End-of-Life 2021-02-16 2022-03-15
go1.17 End-of-Life 2021-08-16 2022-08-02
go1.18 End-of-Life 2022-03-15 2023-02-01
go1.19 Maintenance 2022-08-02 Q3 2023
go1.20 Current 2023-02-01 Q1 2024
go1.21 Planned Q3 2023 Q3 2024

1.16 及以前的版本

我开始学习 Golang 的时候,已经是 1.5 和 1.6 版本了,更早的版本只需要对重大特性引入时间做一个简单了解。
现在主要的开发版本已经升级到 1.18 和 1.20。

  • 1.0
  • 第一个正式版本,核心特性都已经包含在里面,承诺以后语法不会发生不兼容变化
  • 至今为止,承诺都实现了。后面的版本几乎很少有激动人心的功能,绝大多数时候都是各种改进
  • 1.1
  • 1.2
  • 支持 slice[low:high:max] 语法
  • 1.4
  • for range 语法引入
  • 1.5
  • 实现自举
  • 1.9
  • type alias 语法引入
  • 1.11
  • Go Modules 引入
  • 1.12
  • 开始支持 TLS 1.3
    • 需要通过 GODEBUG=tls13=1 开启(不能通过 tls Config MaxVersion 限制版本)
    • 0-RTT 不被支持(到 2023 年,依然没有提供支持
  • 1.13
  • TLS 1.3 默认开启
  • 1.14
  • TLS 1.3 成为默认选项,并且无法通过 GODEBUG 关闭
  • 异步可抢占 goroutine
  • 1.16
  • Go Modules 成为默认(GO111MODULE = on
  • 支持将静态文件打包进可执行文件(//go:embed
  • 弃用 io/ioutil

参考:

1.17

  • Module graph pruning(依赖图修剪)
  • 切片转数组指针

参考:

1.18

  • 泛型(Golang 发布以来最大的语法变更)
  • fuzzing(模糊测试)
  • TLS 客户端默认版本改为 1.2

参考:

1.19

没有特别值得关注的的改动。

参考:

1.20

  • 切片转数组

参考:

1.21

  • min, maxclear
  • 循环变量捕获 (loop variable capture)
    参见:2023/07/05,Go 1.21 for 语义变更
  • 标准库:log/slog, slices, maps, cmp

参考:

#782 DDD: 领域驱动设计

2022-04-09

我们的业务逻辑实际上与程序架构、数据库、缓存等严重耦合在一起,我一直觉得这是一种糟糕的设计。在我的想象中,最完美的情况是程序的核心应该用一种接近自然语言的 DSL(领域特定语言)来完整描述业务逻辑。

开发业务的人,谁关心我们的对象是在堆上还是在栈上,谁关心物理服务器是什么型号,甚至我们连数据库提供的功能都不愿多用,想尽可能减少对指定数据库的依赖。现在的服务网格也在剥离程序自身的一些架构方面的控制逻辑。

随着程序设计不断地剥离非业务逻辑的趋势,在不远的未来,早晚会实现我所想象的这种开发模式。

可能说的有点远,有点大。至少,就程序员熟悉的分层这种拆分复杂逻辑的思想来说,我们应该尽可能只采用程序设计语言的基础语法,没有任何外部依赖地,描述业务逻辑。这样的代码不是更容易理解,更方便审计,更便于维护吗?同时还更健壮。

我觉得我的这些想法和 DDD 不谋而合。

注意:DDD 适用于领域复杂度高、需要长期维护和扩展的业务系统。但对于简单的 CRUD 应用,引入了更多抽象,带来不必要的复杂性,还是应该短平快一些。
注意:重点是灵活应用设计思想,让架构为业务服务,而不是为了架构而架构。

核心思想

  1. 程序的核心的是业务逻辑的描述,贴近业务,而不是整个系统围绕着数据库,然后业务逻辑和技术实现混杂在一起,分散在程序的各处,可能叫做 XXXController、XXXService、XXXUtil。
  2. 划分子模块(),不同子模块之间通过 API、消息队列、事件驱动等方式进行通信,而不是共享数据。
  3. 强调统一描述,对问题的描述中不要增加业务实现的部分,增加团队沟通成本。
    比如:订单状态包括用户未支付、用户已支付、商家确认、商家备货、商家发货、物流发货、物流配送、用户签收、订单完成、订单取消、订单退款等等状态,存储在数据库里面可能是一个 int 类型字段,
    如果在代码中订单状态变更写的是 setStatus(1)、setStatus(2)、setStatus(3),这样做是非常糟糕的。
    如果这样的表述出现在内部沟通中,除了做这个开发的人,其他人看到也是一脸懵。
    所以状态的状态

领域驱动设计

DDD(Domain-Driven Design,领域驱动设计)是一种软件设计方法,强调软件设计应该以业务领域为中心,而不是以技术为中心。DDD 由 Eric Evans 在 2003 年提出。

领域驱动设计(Domain-Driven Design,简称 DDD)是一种以 业务需求 为核心的软件设计方法,强调 构建符合业务逻辑的领域模型,并通过 明确的边界良好的架构设计 来提升软件的可维护性和可扩展性。DDD 主要包括两个核心部分:战略设计战术设计

战略设计(Strategic Design)

战略设计关注如何合理划分业务领域,确定子系统的边界,并定义它们之间的关系。核心概念包括:

界限上下文(Bounded Context)

界限上下文是业务系统中的一个独立单元,包含特定的业务逻辑、数据模型和规则。不同上下文之间通过清晰的接口 进行交互,以避免模型混乱。

领域(Domain)与子域(Subdomain)

  • 领域(Domain):指整个业务范畴,例如“电子商务”“订单管理”等。
  • 子域(Subdomain):将复杂业务拆分为多个独立子域,例如在电子商务系统中,可能包含“商品管理”“订单管理”“支付处理”等子域。
    • 核心子域(Core Subdomain):业务的核心竞争力,最需要投入设计和优化的部分。
    • 支撑子域(Supporting Subdomain):为核心业务提供支持的部分,例如 CRM、客服管理等。
    • 通用子域(Generic Subdomain):可以复用的领域,如用户认证、日志管理等。

战术设计(Tactical Design)

战术设计关注如何在代码层面 实现领域模型,确保业务逻辑的清晰表达和长期可维护性。核心概念包括:

领域模型(Domain Model)

领域模型是对业务逻辑的抽象,主要由以下组成部分:

  • 实体(Entity):具有唯一标识(ID)的对象,状态可能随时间变化,例如“订单”“用户”等。
  • 值对象(Value Object):无唯一标识,通常用于描述属性,如“地址”“货币金额”。
  • 聚合(Aggregate):由多个实体和值对象组成的业务单元,具有一致性约束。
  • 聚合根(Aggregate Root):聚合的核心实体,负责维护聚合内部的一致性,对外提供访问接口。

仓储(Repository)

仓储模式用于 管理实体的持久化,屏蔽底层数据库操作,提供对象级的访问方式。例如 OrderRepository 负责管理订单的存取。

领域服务(Domain Service)

当某些业务逻辑无法归属于单个实体时,使用 领域服务(无状态)。例如“计算订单折扣”可能涉及多个对象,可放在 OrderDiscountService 中。

领域事件(Domain Event)

领域事件用于 表示业务中的重要事件,支持异步处理和系统解耦。例如“订单已支付”可以触发多个后续操作(发货、通知用户等)。

其他类似名词

  • BDD(Business-Driven Development,业务驱动开发):强调通过业务需求来驱动开发过程,通常使用自然语言编写测试用例。
  • BDD(Behavior-Driven Development,行为驱动开发):强调通过行为来定义软件功能,通常使用 Gherkin 语言编写测试用例。
  • FDD(Feature-Driven Development,特性驱动开发):强调通过特性来驱动开发过程,每个特性都是一个可交付的增量。
  • TDD(Test-Driven Development,测试驱动开发):强调在编写代码之前先编写测试用例,通过测试驱动代码的实现。

参考资料与拓展阅读

#781 SMPP 短信协议

2022-04-07

https://en.wikipedia.org/wiki/Short_Message_Peer-to-Peer
https://smpp.org/

Short Message Peer-to-Peer (SMPP) 是一种开放的短信协议。虽然名字中带有 P2P 的字样,但 SMPP 实际上是一种 C/S 协议。
移动 CMPP 协议,联通 SGIP 协议,电信 SMGP 协议,据说他们之间交换信息都是走 SMPP 协议。

常用版本:

根据维基百科的资料,SMPP 之前由 SMS 论坛开发,但是 2007 年,SMS 论坛已经解散了。

数据格式

数据包(PDU (protocol data units, or packets))格式:

  • header (必需)
  • command_length 4B
  • command_id 4B
  • command_status 4B
  • sequence_number 4B
  • body (可选)
'command_length',             (60) ... 00 00 00 3C
'command_id',                  (4) ... 00 00 00 04
'command_status',              (0) ... 00 00 00 00
'sequence_number',             (5) ... 00 00 00 05

'service_type',                 () ... 00
'source_addr_ton',             (2) ... 02
'source_addr_npi',             (8) ... 08
'source_addr',               (555) ... 35 35 35 00
'dest_addr_ton',               (1) ... 01
'dest_addr_npi',               (1) ... 01
'dest_addr',           (555555555) ... 35 35 35 35 35 35 35 35 35 00
'esm_class',                   (0) ... 00
'protocol_id',                 (0) ... 00
'priority_flag',               (0) ... 00
'schedule_delivery_time',      (0) ... 00
'validity_period',             (0) ... 00
'registered_delivery',         (0) ... 00
'replace_if_present_flag',     (0) ... 00
'data_coding',                 (3) ... 03
'sm_default_msg_id',           (0) ... 00
'sm_length',                  (15) ... 0F
'short_message', (Hello Wikipedia) ... 48 65 6C 6C 6F 20 57 69 6B 69 70 65 64 69 61

名词

  • SMSC:short message service center,服务器端
    或者叫 Messaging Center,简写作 MC
  • ESME:extended short message entity,客户端

命令

Command ID Value
generic_nack 0x80000000
bind_receiver 0x00000001
bind_receiver_resp 0x80000001
bind_transmitter 0x00000002
bind_transmitter_resp 0x80000002
query_sm 0x00000003
query_sm_resp 0x80000003
submit_sm 0x00000004
submit_sm_resp 0x80000004
deliver_sm 0x00000005
deliver_sm_resp 0x80000005
unbind 0x00000006
unbind_resp 0x80000006
replace_sm 0x00000007
replace_sm_resp 0x80000007
cancel_sm 0x00000008
cancel_sm_resp 0x80000008
bind_transceiver 0x00000009
bind_transceiver_resp 0x80000009
Reserved 0x0000000A / 0x8000000A
outbind 0x0000000B
Reserved 0x0000000C - 0x00000014 / 0x8000000B - 0x80000014
enquire_link 0x00000015
enquire_link_resp 0x80000015
Reserved 0x00000016 - 0x00000020 / 0x80000016 - 0x80000020
submit_multi 0x00000021
submit_multi_resp 0x80000021
Reserved 0x00000022 - 0x000000FF / 0x80000022 - 0x800000FF
Reserved 0x00000100
Reserved 0x80000100
Reserved 0x00000101 / 0x80000101
alert_notification 0x00000102
Reserved 0x80000102
data_sm 0x00000103
data_sm_resp 0x80000103
Reserved for SMPP extension 0x00000104 - 0x0000FFFF / 0x80000104 - 0x8000FFFF
Reserved 0x00010000 - 0x000101FF / 0x80010000 - 0x800101FF
Reserved for SMSC Vendor 0x00010200 - 0x000102FF / 0x80010200 - 0x800102FF
Reserved 0x00010300 - 0xFFFFFFFF

总结:

RequestCommandID ComandValue 十进制 说明
bind_receiver 0x00000001 1 建立接收会话(接收上行)
bind_transmitter 0x00000002 2 建立发送会话(提交下行)
query_sm 0x00000003 3 查询
submit_sm 0x00000004 4 提交
deliver_sm 0x00000005 5 下发(状态报告或上行)
unbind 0x00000006 6 中断连接
replace_sm 0x00000007 7 替换已提交消息
cancel_sm 0x00000008 8 取消
bind_transceiver 0x00000009 9 建立会话(发送 + 接收)
outbind 0x0000000B 11 通知客户端建立连接(bind_receiver )
enquire_link 0x00000015 21 心跳
submit_multi 0x00000021 33 批量提交(多个收件人)
alert_notification 0x00000102 258 -
data_sm 0x00000103 259 submit/deliver 的替代方案
  • 响应:对应请求 + 0x80000000
  • outbindalert_notification 没有对应响应
  • 此外,还有 generic_nack 是通用拒绝响应(0x80000000
  • outbind 的场景是服务器端需要推送信息或状态给客户端

#780 ABNF 语法

2022-04-07

BNF,Backus-Naur Form,或者 Backus Normal Form,巴科斯范式
用来准确地描述一种计算机语言的语法规则,所以可以理解成是 “语言的语言”。

约翰·巴科斯(美国)首次在 ALGOL 58 中实现巴科斯范式。彼得·诺尔(丹麦)在 ALGOL 60 之中,进一步发展它的概念并将它的符号加以简化,称其为巴科斯范式(Backus Normal Form)。但高德纳主张应称为巴科斯-诺尔范式(Backus–Naur Form),因为它不算是一种正规形式(Normal Form)。

BNF 有两种常见变体:

  • ABNF,扩充巴科斯范式
  • EBNF,扩展巴科斯范式

不用深究 BNF,EBNF,ABNF,或者什么 xBNF 之间到底有什么区别,在需要开发语法解析器之前,只用知道这些是现在最主流的语法语言就行了。

这篇文章讨论的就是 Internet 领域常用的 ABNF。

(ABNF)它是由第68号互联网标准定义的,也就是RFC 5234,经常用于互联网工程任务组(IETF)通信协议的定义语言。

规则

ABNF 语法描述就是一组规则,每个规则分成规则名称、规则说明两部分。
PS:规则说明可以引用其他的规则。

RFC#822 Internet Message Format 中的例子:

date-time       =       [ day-of-week "," ] date FWS time [CFWS]

day-of-week     =       ([FWS] day-name) / obs-day-of-week

day-name        =       "Mon" / "Tue" / "Wed" / "Thu" /
                        "Fri" / "Sat" / "Sun"

date            =       day month year

PS:这里只是截取的部分,没有列出来的规则在别处声明。

参考资料与拓展阅读

#779 CMPP/SGIP/SMGP

2022-04-05
  • SMS: Short Message Service, 短信
  • GSM: Global System for Mobile Communications,全球移动通信系统
  • SP: Service Provider,服务商
  • SMG: Short Message Gateway,短信网关, 作为 SMC 对外提供的接口,处理不同系统之间的短信交换(SMC 之间,SP 和 SMC 之间)
    部分资料也写作 SMGW,ISMG (Internet Short Message Gateway)
  • GNS: Gateway Name Server, 网关名称服务器(汇接网关),类似 DNS
  • SMC: Short Message Center,短信中心
  • PSTN: Public Switched Telephone Network,公用电话网络
  • ISDN: Integrated Services Digital Network,综合数字网络
  • MSISDN: Mobile Subscriber Integrated Services Digital Network,移动用户数字网络
  • SMPP: Short Message Peer-to-Peer,短信点对点协议 https://smpp.org/

对于开发者,只用了解协议中与 SP 相关的部分,也就是 SP 和 SMG 打交道的部分。

SP 的 SMS 要进入 SMC 需要走 SMG。

手机号的国际规范: ITU-T E.164

中国移动 CMPP (China Mobile Peer to Peer)

https://baike.baidu.com/item/CMPP

中国移动点对点协议
中国移动通信互联网短信网关接口协议

基于 TCP 协议。

说明:为中国移动通信集团公司企业规范。规范中描述了中国移动短信业务中各网元(包括 ISMG、 GNS 和 SP)之间的相关消息的类型和定义。

规范中定义了以下三方面的内容:

  1. 信息资源站实体与互联网短信网关之间的接口协议;
  2. 互联网短信网关之间的接口协议;
  3. 互联网短信网关与汇接网关之间的接口协议。

适用于各 SP 和 ISMG 的开发厂商。

中国联通 SGIP (Short Message Gateway Interface Protocol)

https://baike.baidu.com/item/SGIP

中国联合通信公司短消息网关系统接口协议

SGIP 是的英文缩写,是中国联合通信公司短消息网关系统接口协议。

协议说明

本协议是 SMG 和 SP 之间、SMG 和 GNS 之间、以及 SMG 和 SMG 之间的接口协议,简称 SGIP。

通过应用 SGIP 协议,SP 可以接入到 SMG,实现 SP 应用的一点接入、全网服务;SMG 可以通过 SGIP 协议,实现消息在不同 SMG 之间的路由和转发。同时,SMG 通过该协议也可以和 GNS 通信,以实现各 SMG 和 GNS 之间路由表的同步功能。

适用范围

本协议适用于各 SP 厂商和 SMG 的开发厂商。

  1. 号码可随意扩展
  2. 支持全国联通上下行
  3. 支持 300 字长短信
  4. 可提供二次开发接口

中国电信 SMGP (Short Message Gateway Protocol)

短消息网关协议

https://baike.baidu.com/item/SMGP
https://wenku.baidu.com/view/fc13c7116c175f0e7cd1379b.html
https://wenku.baidu.com/view/b7f17df0fe4ffe4733687e21af45b307e971f9db.html 3.0.1
https://wenku.baidu.com/view/cf3e1ae4866fb84ae55c8d3a.html 3.0.3

SMGP 协议简称

定义

SMGP 协议是 SMGW 与其它网元设备(除 SMC 外)进行短消息传输的接口协议。
非 SMC 网元设备向 SMGW 发送或从 SMGW 接收短消息,这些非 SMC 网元设备称为 ESME。

通信方式

SMGW 与 ESME 之间共有两种连接方式:长连接和短连接。所谓长连接,指在一个 TCP 连接上可以连续发送多个数据包,在 TCP 连接保持期间,如果没有数据包发送,需要双方发链路检测包以维持此连接。短连接是指通信双方有数据交互时,就建立一个 TCP 连接,数据发送完成后,则断开此 TCP 连接,即每次 TCP 连接只完成一对 SMGP 消息的发送。

#778 Jumpserver 开源堡垒机

2022-04-05

架构

Arch

Core 是 JumpServer 的核心组件,由 Django 二次开发而来,内置了 Gunicorn Celery Beat Flower Daphne 服务。

Lina 是 JumpServer 的前端 UI 项目,主要使用 Vue,Element UI 完成。
Luna 是 JumpServer 的前端 UI 项目,主要使用 Angular CLI 完成。

  • Koko 是 Go 版本的 coco,重构了 coco 的 SSH/SFTP 服务和 Web Terminal 服务。SSH
  • Lion未开源 使用了 Apache 软件基金会的开源项目 Guacamole,JumpServer 使用 Golang 和 Vue 重构了 Guacamole 实现 RDP/VNC 协议跳板机功能。RDP VNC
  • Magnus未开源 是 JumpServer 的数据库安全连接组件,支持多种数据库协议,使用 Golang 实现。Redis MySQL
  • Razor:官网没有提供相关介绍,根据 Release Notes 描述,可能是付费版本的 RDP 录像组件。

#777 mpv 播放器

2022-04-04

快捷键

  • Left/Right:快进, 快退
  • Up/Down:快进, 快退
  • [/]:倍速 x0.9, x1.1
  • {/}:倍速 x0.5, x2
  • Space (p):暂停/播放
  • ,/.: 暂停,然后逐帧前进,逐帧后退
  • 9/0: 音量
  • s: 截图
  • q: 退出
  • v: 字幕开关
  • j: 切换字幕
  • o: 显示进度
  • f: 全屏开关
  • i: 显示视频信息
  • #: 切换音轨
  • l: 设置循环 A-B 点, 循环播放,清除循环

配置

系统配置:/etc/mpv/mpv.conf

cat /etc/mpv/mpv.conf
hwdec=vaapi

用户配置 (需要自己创建):

  • ~/.config/mpv/mpv.conf
  • ~/.config/mpv/input.conf
  • ~/.config/mpv/fonts.conf
  • ~/.config/mpv/script-opts/osc.conf
no-border

idle=yes

osd-font-size=24
save-position-on-quit

hwdec=auto

screenshot-directory=~/Pictures/Screenshots
screenshot-format=png
screenshot-template="%tY%tm%td-%tH%tM%tS-mpv-%F-%wH%wM%wS%wT"
mkdir -p ~/.config/mpv/scripts ~/.config/mpv/script-opts
find ~/.config/mpv/ -ls

GH=https://raw.githubusercontent.com
wget $GH/jonniek/mpv-menu/master/menu.lua -P ~/.config/mpv/scripts/
wget $GH/jonniek/mpv-playlistmanager/master/playlistmanager.lua -P ~/.config/mpv/scripts/
wget $GH/jonniek/mpv-playlistmanager/master/playlistmanager.conf -P ~/.config/mpv/script-opts/
wget $GH/jonniek/mpv-playlistmanager/master/menu.json -P ~/.config/mpv/script-opts/

#775 Go 语言有什么优势

2022-04-02
  • 语法简单
  • 确实没有很多语言特性,容易上手,但说什么大道至简,Less is more 等价值观就有点扯了。
  • 静态类型、强类型、编译型语言
  • 性能
  • 并发:自带的协程实现(goroutine + channel)在开发效率和性能之间达成了一个不错的平衡,非常优秀
  • 跨平台
  • 接口,反射,GC
  • C 嵌入
  • 便于工程化:工具链齐全,代码规范严格
  • 没有历史负担:但是向前兼容的承诺也是
  • Go1 兼容性承诺(最重要特性之一):但是也令人担忧,时间一长,可能就有太重的包袱
  • 基于消息传递的通信机制
  • 核心开发团队名气非常大
  • robert griesemer
  • rob pike
  • ken thompson
  • russ cox
  • 生态:有大公司站台,有杀手级项目(Docker, K8S 等)

存在的问题

  1. 异常处理的设计
  2. 标准库相对太薄弱
  3. 生态:缺乏主流框架
  4. 包管理机制上存在的问题
  5. 没有泛型(1.18 以前)

场景

  • 云原生
  • 基础设施项目
  • Web 开发
  • 网络编程

#774 解释解释什么叫 “包容性命名”

2022-04-02

开发者想必都有耳闻,过去一两年间,因为一些美国政治风波的影响,各大社区都被政治正确问题所困扰,然后有一些相关改名的操作。
PS: 连黑人牙膏(高露洁旗下)都改名 “好来牙膏” 了。

最著名的可能就是 GitHub 中的默认主干分支从 master 改成 main,然后很多项目宣布将主从表述由 master/slave 改成 primary/replica,黑名单 Blacklist 改叫 Denylist 或者 Blocklist。

我最近听说有个叫包容性命名促进会的组织(Inclusive Naming Initiative)。
https://inclusivenaming.org/

他们列了一个清单,将开发过程中常用的一些有冒犯性的词,按照冒犯级别分三类,然后还给出来一些他们建议的替换词。