标签归档:go

[转译] 别墨迹了,用 Go 就完事了

来源:Just Fucking Use Go – Blain Smith

说明:本文为 AIGC 辅助翻译整理版本(对原文各段落做了转述与浓缩,非逐句全文翻译),已进行简单人工校对,具体细节请自行甄别,建议参阅原文。

别墨迹了,用 Go 就完事了

文章标题原文相当直给:两秒编译完成、打包成单个二进制文件、凌晨三点某个 npm 依赖被撤包也不会让你的服务崩掉——作者说的就是 Go。就像 HTML 早就摆在那里等前端别再自己找罪受一样,Go 也已经在那儿蹲了十几年,等着后端工程师别再把简单问题复杂化。

但现实是,很多团队还在用十几个 Node 包、三套 TypeScript 构建工具,外加一整套 Kubernetes 集群,去撑起一个普普通通的表单提交。有人专门养了一个平台团队去伺候 Rails 单体应用,也有人说服 CTO 用 Rust 重写一个每秒撑死几十个请求的 CRUD 应用。作者的评价很直接:这是自己给自己挖坑。

“无聊”是设计出来的

Go 语言读起来”无聊”,作者认为这正是它的优点——没有装饰器、没有元类、没有宏,也没有 Haskell 圈子里那些让人头晕的 trait、monad。只有结构体、函数、接口、goroutine 和 channel。语言规范可以在午休时间读完,下午就能上手写代码。

“无聊”意味着新人能看懂两年前资深工程师写的代码;gofmt 已经统一了格式,团队里没人能靠”炫技”往代码库里塞十七层抽象——因为语言本身不允许。

标准库就是框架

作者的态度很硬:别找框架了,标准库本身就是框架。文章给出了一个用 net/httphtml/templateembed 写成的最小 Web 应用示例——HTML 模板直接编译进二进制文件,没有 webpack、没有 Vite、没有体积堪比一辆汽车的 node_modulesgo build 之后就是一个可执行文件,扔到服务器上就能跑。

数据库用 database/sql,JSON 用 encoding/json,想调用其他服务照样用 net/http(它同时也是客户端),想并发就在函数调用前加一个 go 关键字,测试用 go test,基准测试用 go test -bench,性能分析工具 pprof 早就内置好了。

标准库的深度也体现在几个关键抽象上:io.Reader/io.Writer 这两个各只有一个方法的接口,撑起了整个生态里”管道式”处理数据流的能力;context.Context 负责统一取消信号的传递——用户关掉浏览器标签页,HTTP 请求、数据库查询、下游调用会一路跟着取消,不会留下泄漏的 goroutine 或吃满连接池的僵尸查询;而 encoding/jsonencoding/xmlencoding/csv 等编码包用的是同一套 struct tag 和”解码进指针”的写法,学会一个基本就等于都会了。

并发不用哭着写

Goroutine 不是线程,它是由运行时调度、复用在系统线程之上的有栈协程,启动成本大约 2KB,一台笔记本上开十万个都不成问题。文章举了一个用 channel 并行抓取多个 URL 的例子:给每个请求起一个 goroutine,把结果丢进 channel,主流程再依次读出来——没有额外的库,没有 async/await 的仪式感,语言原生就把这件事做了。

一个不是 Hello World 的例子

作者贴出一段真实感更强的代码:一个从 Postgres 读数据、渲染 HTML 的 CRUD 路由,把数据库查询、模板渲染和 HTTP handler 全部塞进一屏代码里,请求的 context 一路传到 SQL 查询,连接一断查询就跟着取消。没有 ORM,没有依赖注入容器,没有 service 层,也没有塞满一堆抽象基类的 controllers/ 目录——从头读到尾就知道它在干什么。

依赖管理不折腾人

go mod init 之后,依赖就活在 go.modgo.sum 两个文件里,后者是你实际拿到的依赖内容的哈希记录,一旦有人悄悄替换包内容就能被发现。没有体积惊人的 node_modules,没有开发环境和 CI 之间的 lockfile 漂移,也没有 peerDependencies、devDependencies 那一堆概念。需要离线构建就用 go mod vendor,把全部依赖打进 vendor/ 目录,工具链自动识别,整个项目连同依赖打成一个 tar 包就能带走。

工具链是编译器自带的

gofmt 统一代码格式,没有类似 .prettierrc 那样的风格之争;go vet 挑出明显的错误;go test 跑测试,加上 -race 参数就能带着竞态检测器跑,-bench 做基准测试,-cover 看覆盖率;go tool pprof 能从正在运行的线上服务里,通过两行代码接入的 HTTP 端点直接拉出 CPU 和内存的火焰图。这些统统是标准工具链自带的能力,不用装插件,也不用维护额外的配置文件。

部署就是一条 copy 命令

这大概是最让 Rails / Node 阵营破防的部分:编译出一个 Go 二进制文件,scp 到服务器,systemctl restart 一下,三条命令,部署完成。没有 Dockerfile,没有多阶段构建,没有每周准时弹出的基础镜像 CVE 警报,没有 Kubernetes manifest、没有 Helm chart、没有 ArgoCD、没有 service mesh、没有 sidecar。一个十几 MB 的静态链接二进制文件加一份二十行的 systemd 配置,就是一次能用很多年的生产部署。

“那 Rails / Django / Express / Next 呢?”

作者一一吐槽:Rails 的部署要靠 Capistrano、一堆配置文件外加运气;Django 要求你学它的 ORM、admin、中间件体系以及一整套设计哲学;Express 靠 npm audit 的警告和祈祷维持运转;Next.js 则是隔三差五换一次路由约定,还一副理所当然的样子。相比之下,Go 编译出来的二进制文件不挑环境,五年后大概率还能在当时还不存在的硬件上继续跑。

“那微服务呢?”

作者的回答很干脆:不需要。先老老实实写一个 Go 单体应用,配一个 Postgres,顶多再加一个 Redis;HTML 页面和 JSON API 走同一个端口;跑在一台比每月奶咖开销还便宜的 VPS 上,扛到每秒一万请求都不会吃力,因为 Go 本身就是为这种场景设计的,goroutine 足够廉价。真到了需要拆分的那一天(作者认为多数团队根本用不上),拆一个 Go 单体应用无非是把已经存在的包挪进各自的仓库——接口边界早就在那儿了,是语言本身逼着你这么设计的。

“那泛型呢?那没有异常的错误处理呢?”

在作者看来,if err != nil 是特性而不是缺陷:它逼着你正视每一个可能出错的地方,并当场决定怎么处理,而不是像层层嵌套的 try/catch 那样把错误一路藏到深夜的生产事故里才暴露出来。至于泛型,Go 1.18 就已经加上了,需要的时候用就是了,没什么好纠结的。

别墨迹了,用 Go 就完事了

作者的结论很简单:不需要框架,也不需要微服务、Rust 重写,或者上周才发布、号称能拯救一切的 JavaScript 元框架。打开编辑器,go mod init,写一个 main.go,把模板嵌进去,编译,发布——”无聊”的选择,往往就是对的选择。

极简但强大的个人财务管理软件 —— 溪流记账(Rivulet)

从开始工作,就一直想开发一款面向个人的财务管理软件,用来直观的分析自己的财务状况,对个人财务情况提供直观的反馈,帮助自己更好的存钱、消费和投资。获取正向反馈,激励自己更好的存钱。

此前,基于 Notion 制作过一套个人财务管理模版,取名 BJ-PFD , 是一长串英文的缩写:Bullet Journal – Personal Finance Dashboard,意为子弹笔记个人财务仪表盘。之前写过一系列的 文章 介绍这套模版。这套模版我个人也一直在用,从2020年到2026年,已经使用了6年了,积累了大量的财务数据,帮助我更好的分析和管理个人财务状况。数据条数也增加到好几千条。此时我发现 Notion 的一些弊端暴露出来了。比如,数据库数量大了以后,加载会比较慢,而且一些数据关联会有极小概率出现问题,导致最终的数据统计出现细微的差错。更重要的一个问题,随着我数据的变多,基于 Notion API 开发的看板工具,启动速度越来越慢了,每次统计数据都要花费数分钟来加载数据。

最近,结合自己之前的工作流和数据模型,使用 AI 辅助编程开发了这款软件。经过一段时间的调试和打磨,这款软件已经能够完美承载我个人目前的财务管理需求,我也将 Notion 中的数千条数据,顺利导入这款新的软件中,数据统计速度从1分钟以上,提升到了1秒以内。现在我已经完全迁移到这款软件上了,使用体验非常好。现在,我希望将这款软件发布出来,分享给更多有需要的人使用。

下面是关于这款软件的介绍:

Rivulet 简介

溪流记账(Rivulet)是一款极简但强大的个人财务管理软件,支持快速记录收支、多账户、多账本与共享账本;提供预算管理、投资记录与财务分析。

Rivulet 使用 GO 和 Svelte 开发,使用 Docker 封装并公开发布,支持 SQLite 和 PostgreSQL 数据库。

更多信息,可以进入 Rivulet 的 官网GitHub Docs仓库 查看,如果有问题可以直接在 留言板 或是 GitHub Docs 仓库的 Issues/Discussions 提出。

Rivulet 功能介绍

  • 支持灵活的流水管理功能,区分支出、收入和转账,并支持灵活的分类,可以方便的进行流水统计;
  • 支持财务规划功能,在财务规划界面可以方便的进行每月收入、支出的预算规划,并查看实时的预算执行情况;
  • 支持投资管理,提供方便的投资买入、卖出、分红记录,投资记录自动生成流水记录,并提供投资盈亏分析;
  • 支持账户管理,方便关联自己实际的各个账户;
  • 支持多账本,账本间的流水互相隔离,适合不同的使用场景,比如个人账本、家庭账本、公司账本等;支持账本共享。
  • 更多功能陆续开发中。

Rivulet 截图

Rivulet dashboard 2026 05 07 22 29 38 Rivulet transactions 2026 05 07 22 29 51 Rivulet budgets 2026 05 07 22 35 12 Rivulet investments 2026 05 07 22 35 26 Rivulet ledgers 2026 05 07 22 35 37 Rivulet accounts 2026 05 07 22 35 45 Rivulet settings 2026 05 07 22 36 01

最后,欢迎大家试用这款软件,如果有任何疑问随时与我交流,也欢迎大家提出宝贵的意见和建议,帮助我一起把这款软件做得更好。

Refs

go 拉取 gitcode.com 私有 mod

TL;DR

某个项目 mod 托管在 gitcode,无法拉取。git 登陆也不行,需要配置 git 针对 gitcode 默认走 ssh 协议:

git config --global url."ssh://git@gitcode.com".insteadOf "https://gitcode.com"

在网上查到比较多的是针对 gitlabgithub 的:

# gitlab
git config --global url."ssh://git@gitlab-company".insteadOf "https://gitlab.xxx.cn"

# github的同理
git config --global url."ssh://git@github-company".insteadOf "https://github.com"

配置后就可以正常 go mod tidy 了。

Refs

分享一个快捷内网、漏洞扫描工具 fscan

fscan 是一款 go 语言写成 “一款内网综合扫描工具,方便一键自动化、全方位漏扫扫描”。是我在刷 kon9chunkit 发起的 GitHub中文排行榜 时发现的。

该工具支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写公钥、计划任务反弹shell、读取win网卡信息、web指纹识别、web漏洞扫描、netbios探测、域控识别等功能。

用来快速扫描局域网主机存活也是很好的,下面简单介绍使用方法:

安装很简单,装好 go 环境编译一下就行:

$ git clone https://github.com/shadow1ng/fscan.git
$ cd facan
$ go build -ldflags="-s -w " -trimpath

之后就可以进行扫描了,快速进行局域网段扫描:

$ ./fscan -h 192.168.123.0/24 

   ___                              _    
  / _ \     ___  ___ _ __ __ _  ___| | __ 
 / /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__|   <    
\____/     |___/\___|_|  \__,_|\___|_|\_\   
                     fscan version: 1.6.3
start infoscan
已完成 0/0 listen ip4:icmp 0.0.0.0: socket: operation not permitted
The current user permissions unable to send icmp packets
start ping
(icmp) Target '192.168.123.9' is alive
(icmp) Target '192.168.123.4' is alive
...
icmp alive hosts len is: 7
192.168.123.3:443 open
...
alive ports len is: 19
start vulscan
[*] WebTitle:http://192.168.123.1      code:401 len:140    title:401 Unauthorized
.....

完整支持参数如下:

    -c string
        ssh命令执行
  -cookie string
        设置cookie
  -debug int
        多久没响应,就打印当前进度(default 60)
  -domain string
        smb爆破模块时,设置域名
  -h string
        目标ip: 192.168.11.11 | 192.168.11.11-255 | 192.168.11.11,192.168.11.12
  -hf string
        读取文件中的目标
  -hn string
        扫描时,要跳过的ip: -hn 192.168.1.1/24
  -m string
        设置扫描模式: -m ssh (default "all")
  -no
        扫描结果不保存到文件中
  -nobr
        跳过sql、ftp、ssh等的密码爆破
  -nopoc
        跳过web poc扫描
  -np
        跳过存活探测
  -num int
        web poc 发包速率  (default 20)
  -o string
        扫描结果保存到哪 (default "result.txt")
  -p string
        设置扫描的端口: 22 | 1-65535 | 22,80,3306 (default "21,22,80,81,135,139,443,445,1433,3306,5432,6379,7001,8000,8080,8089,9000,9200,11211,27017")
  -pa string
        新增需要扫描的端口,-pa 3389 (会在原有端口列表基础上,新增该端口)
  -path string
        fcgi、smb romote file path
  -ping
        使用ping代替icmp进行存活探测
  -pn string
        扫描时要跳过的端口,as: -pn 445
  -pocname string
        指定web poc的模糊名字, -pocname weblogic
  -proxy string
        设置代理, -proxy http://127.0.0.1:8080
  -user string
        指定爆破时的用户名
  -userf string
        指定爆破时的用户名文件
  -pwd string
        指定爆破时的密码
  -pwdf string
        指定爆破时的密码文件
  -rf string
        指定redis写公钥用模块的文件 (as: -rf id_rsa.pub)
  -rs string
        redis计划任务反弹shell的ip端口 (as: -rs 192.168.1.1:6666)
  -silent
        静默扫描,适合cs扫描时不回显
  -sshkey string
        ssh连接时,指定ssh私钥
  -t int
        扫描线程 (default 600)
  -time int
        端口扫描超时时间 (default 3)
  -u string
        指定Url扫描
  -uf string
        指定Url文件扫描
  -wt int
        web访问超时时间 (default 5)

总之是一款很实用的工具,平时有很多场景可以使用到。

参考文献