书评:《从一到无穷大》

久闻大名的一本书,但是也一直没怎么读过。这次看完从观感上来说比《时间简史》要强,霍金说一本书公式的数量和读者的数量成反比,但是涉及到科学理论时公式数量和易读性是成正比的,《时间简史》读了两三遍,每次都被大段的文字缠住,不太享受。这本书有相对较多的公式,并不艰深,且对于主题论述有着很好的补充和对照作用。除了公式之外,这本书的主题范围非常广,从数学、物理、天文到生物都涵盖了,每一部分虽不深入,但也都点到了一些比较重要的话题。

这本书本是像抱着了解作者风格的角度来读的,但是也确实是获取到了一些新的知识(或者复习了早就遗忘的知识),比如虚数 i 和旋转角度的对应关系、空间中的手性和转换方法(如二维手性通过莫比乌斯环转换,三维手性通过克莱因瓶转换)、裂变原料如何物尽其用、从随机游走研究分子运动等等,这些内容即使并不全面和深入,也比我零碎了解到的内容系统得多。即使随着时间变化一些理论和数值略有舛误(在写作时确是正确的),也不对这本书的阅读体验有什么影响。

有的内容浅浅看过一遍并不能完全理解,尤其是第四章相对论的部分,闵氏时空的分析我并没有完全看懂,但也并不想再翻过来多看两遍了,之后有机会再说吧。

这本书的质量很高,非常适合科普阅读。

阅读更多

书评:《刀锋》

听到过很多人安利这本书,不过全本读下来并不怎么沉浸,剧情平淡占一部分因素,因时代偏移而有的别扭的对话习惯同样是一部分原因,还有毛姆文字中的气息也是一部分因素。书中的文字被频繁的对话打断,像冬天干冷的雪一样又沙又散。文中又很多对于 “人的一生应该怎么过” 的探讨,读下来颇能静心思考,这是这本书优秀的一点。

这本书是一部群像剧,重点交代的人有艾略特·谈波登,艾略特的外甥女伊莎贝儿,伊莎贝儿前期的情侣拉里,拉里的朋友和伊莎贝儿的丈夫格雷,伊莎贝儿一行人青年时的朋友索菲,还有妓女苏珊。艾略特一辈子都在追求跻身于上流社会,不计成本地参加各种宴会和宴请别人,在写信回复了最后一次宴会邀请后平静地离开了人世;伊莎贝儿同样追求上流和新奇的生活,但是在丈夫格雷破产后也能共克难关,习惯了清贫的生活,她外表美丽,但是内心又略有冰冷的部分,如毛姆所说 “缺少温柔”,在得知索菲即将和拉里结婚之后给索菲设下了圈套,让她最终走上了自我毁灭的道路;拉里是文中的核心人物,一生都在追求生活的真谛,年轻时在一战中当了空军,目睹了同伴的死亡,因为对生活固执的规划而跟伊莎贝儿取消了婚约,后来辗转多地,不断追求、阅读、尝试,最终在印度找到了心灵的宁静,即 “阿特曼”;格雷是富家子弟,但是在大萧条期间破产,后来又在伊莎贝儿和拉里的帮助下重新找回了生活的勇气;索菲在年轻时沉默内敛,内心世界又极其丰富,但是在成年以后横遭变故,沦落到沉溺酒精、毒品和滥交中,后来几乎被拉里拯救了,但是一步走错,最终酿成了横死的下场;苏珊是个妓女,但是一直在琢磨自己的人生,想方设法往上爬,最终与曾经的有钱客户结婚,成了书中下场最好的人之一。

纵观全文的场景,我最喜欢文中拉里和考斯第穿越比利时到德国的这段旅途,恬淡闲适,随着两人走走停停,世界的边界也被不断拓展,路上拉里向考斯第学习德语,遇到村庄时停下来干点农活糊口,太阳一直挂在天上,路一直在脚下,旅途虽然有终点,但是旅行本身没有终点,这种状态真的非常令人向往。

毛姆的行文我并不喜欢,虽然很多人喜欢他的文字,但我有种说不上来的别扭的感觉,再加上第一人称,有点点类似倪匡的《卫斯理》系列中的 “我” 一般,自我的成分过于突出了,且在涉及人生和宗教的话题上,略有些卖弄的嫌疑。读过的第一人称的小说比较自然的好像现在只能想起来张小花的《史上第一混乱》,甚至连他的《史上第一混搭》都有些不自然。

本书值得一读,但是现在想来阅读的过程仍然略难受,或许也有翻译和版本的因素在吧。

阅读更多

书评:《细说明朝》

这本书在好几年前读过,大概是在刚刚对明朝的历史产生兴趣时,彼时觉得其中的皇帝们混乱无序,文臣武将交错驳杂,读这本书更多地只是和《明朝那些事儿》相互对照印证罢了。现在虽然仍然不能完全搞清楚明朝的重要人物,不过好歹能搞清楚皇帝们的传承顺序了,因而这本书读下来感觉全文脉络还是比较清晰的,流畅性也大大提升了。这本书虽名为 “细说”,但是却一点都不细,称为大纲更为合适,毕竟近三百年的历史也没办法在一本书里完全交代,只能浮光掠影地对准那些最显眼的人——好人以及坏人。

翻遍明朝正史中的十六位皇帝,称得上称职的只有太祖、成祖、仁宣二宗、孝宗和穆宗,如果再考虑在位时间和施政连续性,那么就只有太祖、成祖和孝宗三位了(其中成祖穷兵黩武,透支民力过甚,全赖仁宗监国支撑)。除了这六位以外,其他十个基本算得上是一个赛一个地混蛋,尤为混蛋的世宗和神宗也是在位时间最长的两个,占去了不到一百年。明朝有这些皇帝们在竟还能支撑近三百年属实难得,全仰赖前期不错的底子,以及一系列文臣武将的呕心沥血。

阅读更多

书评:《美好的七年》

这应该是最近读的这些书里唯一一本让我常常笑出声的书了。虽然这本书的背景是一位以色列作家在战争期间的生活点滴,但是字里行间丝毫看不出哀怨和喟叹,反而还在短小的篇幅中浸透了幽默感,这并非是没心没肺,而是消解苦难的最佳手段之一。我一向认为诚恳和幽默是最难模仿的两个特质(在苦难中品咂出幽默感更是一种非常高级的技巧,具备这种技巧的作家似乎只能用天赋来解释),本书的作者同时具备这两个特质,这使得这本书的阅读成为了一种享受。

这本书是以色列作家埃特加·凯雷特自述性质的散文集,虽然是散文,但并不全是全无逻辑、充斥着浮夸辞藻和无病呻吟的文字堆积,而是有很精致的结构和很紧实的逻辑,并且内容毫不枯燥,阅读堪称享受。“美好的七年” 从儿子出生开始到七年之后,从战争的片段开始,以战争的片段结束,作者收集了很多生活中和事业上的各种片段,用自己的视角和文笔加工之后写了出来。虽然战争是常驻的背景音,但这本书的主题却不是声讨和反对战争,而是对于生活深刻的热爱,这种发自心底的热爱也同样是文中幽默感的来源。

这本书并不长,但是其中的天地却很宽广,很值得一读。

阅读更多

书评:《菊与刀》

如果谈到世界格局和民族性格,那这本书肯定会出现在推荐列表上。我认为这本书最大的价值尚不在于对于日本人的民族性格的分析,而是在于这种分析的系统性上,这种系统性使得本书可以成为一本人类文化学的教材,从这种系统性中完全可以诞生一门新的学科。

阅读更多

书评:《那不勒斯四部曲》

这四本书是花了十多天一口气读完的,因此也就放在一起写一写。这本书像一部不怎么严肃的意大利近当代史诗,着眼于两个女性的成长——拉法埃拉·赛鲁罗和埃莱娜·格雷科,也即莉拉和莱农,在半个多世纪的荏苒中讨论了童年、友情、亲情、爱情、女性权利、意识形态、社会变迁等等话题。这本书长篇累牍,让我总是不想开始读,直到看到腰封上的 “我的整个生命,只是一场为了提升社会地位的低俗斗争” 这句话——以前听到过这句话,但是这时才知道是出自这本书,于是决定立刻开始读。

第一本书是《我的天才女友》,“天才女友” 指的是莱农(也就是 “我”)从小的朋友莉拉,主要内容是两个人和她们生活的世界在童年和青春期的故事,截止到莉拉的婚礼。

第二本书是《新名字的故事》大概是指莉拉在嫁给斯特凡诺·阿奇勒之后的新名字 “拉法埃拉·阿奇勒”

第三本书是《离开的,留下的》

第四本书是《失踪的孩子》

这本书并不想庸俗地表达什么 “垃圾堆里的百合花” 之类的主题,书中的人物包括主角都并不特别坏也不特别好,刨去事业因素来看就是极其普通的人,这也就让这本书有了在现实中扎根的立足点。

莉拉是一个疏离的人,一个漫不经心的,找不到方向的天才,意识游离在自己的灵魂之外,并不爱自己。莉拉因为家庭因素并没有继续读书,把自己的另一个可能性,自己真正喜欢的另一个可能性寄托在了莱农身上。

阅读更多

2023 年 01 月书单

书名 作者 作者国籍 出版社 类型 评分
潜规则 吴思 中国 复旦大学出版社 社会科学-政治军事 8.5
中国国家地理百科全书:河南、湖北、湖南 张妙弟 中国 北京联合出版公司 自然科学-科学普及 5.0

Docker Multi-Stage Builds

Docker 的 multi-stage 技术可以把不同的构建阶段分离开,方便修改和复用,同时还能更好地把缓存层组合在一起,避免重复劳动,还能保证最后运行时的干净纯粹,不会带入前边阶段的副产品。不过我在实际场景中遇到的问题比单纯的构建更加复杂一些——我不仅需要不同的构建阶段(build stage),还需要在不同的环境里构建同一个镜像,比如在本地和在 CI/CD 中。CI/CD 的特殊之处在于在前边的阶段中基本上已经完成了 dependency download, build, package 等一系列阶段,因此直接把 build 的结果拷贝到 Docker context 里执行 Dockerfile 的最后几步就可以了。如果复用一个 Dockerfile,那么基本上要做前边的很多重复工作,如果用两份 Dockerfile,则又会造成配置上的冗余,迟早会出幺蛾子。

为了解决这个问题,我打算使用 Docker 的 multi-stage 来做,本意是把 package 之后的几步合并到一个 stage 里,在前边的 build 阶段来区分不同的环境。就像下边的配置一样,设想中这个流程非常完美,Docker 可以根据 ENVIRONMENT 来区分不同的环境,并且在最后的 runtime 阶段中从不同的环境构建阶段中把二进制内容拷贝出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM ubuntu:22.04 AS build-base
FROM ubuntu:22.04 AS runtime-base

# 当前环境
ARG ENVIRONMENT=dev

# 本地构建阶段
FROM build-base AS build-dev
RUN build
RUN package
RUN cp . /app

# CI/CD 构建阶段
FROM build-base AS build-prod
COPY . /app

# 最终阶段
FROM runtime-base AS runtime
COPY --from=build-${ENVIRONMENT} /app /app
ENTRYPOINT [ "/app/main" ]

但是这样做有个非常大的问题就是 Docker 的 build arguments 是只在单个阶段之内管用的,因此倒数第二行的 COPY 压根不认识 ENVIRONMENT 这个变量,进而这个 Dockerfile 根本无法正常构建。找了很多解决方案,最终看到虽然在 Docker 某一个阶段内不认识其他阶段的 build arguments,但是在定义阶段本身的时候是可以复用的,也就是 FROM runtime-base AS runtime 这一行,在这里是可以用 ENVIRONMENT 这个变量的。因此思路就很清晰了,可以直接改成下边这种情形:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FROM ubuntu:22.04 AS build-base
FROM ubuntu:22.04 AS runtime-base

# 当前环境
ARG ENVIRONMENT=dev

# 本地构建阶段
FROM build-base AS build-dev
RUN build
RUN package
RUN cp . /app

# CI/CD 构建阶段
FROM build-base AS build-prod
COPY . /app

# 最终阶段
FROM build-${ENVIRONMENT} AS runtime
ENTRYPOINT [ "/app/main" ]

但这样有个最大的问题,就是最后的 runtime 阶段直接继承前边 build 阶段,会把这些阶段运行过程中的副产品、垃圾文件和系统包带到最后,这显然极大地违背了 multi-stage 的初衷。继承还是要继承的,关键是不能从 build 阶段继承,那么自然而然地就想到再加上一层干净的 ready 阶段来过渡,保证 ready 阶段中的内容是纯粹的二进制,每个环境都有自己对应的 ready 阶段,然后分别把自己的二进制拷贝进去就行,如下配置:

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
FROM ubuntu:22.04 AS build-base
FROM ubuntu:22.04 AS runtime-base

# 当前环境
ARG ENVIRONMENT=dev

# 本地构建阶段
FROM build-base AS build-dev
RUN build
RUN package
RUN cp . /app

# CI/CD 构建阶段
FROM build-base AS build-prod
COPY . /app

# 本地准备阶段
FROM runtime-base AS ready-dev
COPY --from=build-dev /app /app

# CI/CD 准备阶段
FROM runtime-base AS ready-prod
COPY --from=build-prod /app /app

# 最终阶段
FROM ready-${ENVIRONMENT} AS runtime
ENTRYPOINT [ "/app/main" ]

这样就可以完美地解决上边的所有问题,除了多出两个几乎一样的 build stages 以外没有什么成本。只要在执行 docker build 的时候传进入对应的 ENVIRONMENT 参数就行。还要注意的是,一定要使用 Docker Buildkit 来执行,这样才会根据最后的 runtime 阶段有挑选地执行需要的阶段,否则 Docker 会傻乎乎地执行所有的阶段,这样就得不偿失了。