summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreltrac <hi@eltr.ac>2026-05-21 11:18:24 +0800
committereltrac <hi@eltr.ac>2026-05-21 11:18:24 +0800
commit28d1a83d54bce3e73675267891dd067fbe38cd93 (patch)
tree037f70da7f4bb79fe03fc34052c36d59bc22349d
parenta28464fc11b092db1449bfd3da464ba13caa0e93 (diff)
[draft] update weekly draft
-rw-r--r--content/weekly/82.md121
1 files changed, 121 insertions, 0 deletions
diff --git a/content/weekly/82.md b/content/weekly/82.md
index ed3e8707..78ff1f2e 100644
--- a/content/weekly/82.md
+++ b/content/weekly/82.md
@@ -15,6 +15,11 @@ toc = true
## 连接
+###
+
+> [!note] 📻
+> [《独树不成林》我抛弃孩子,爱上妈妈,被全欧洲封杀,但我是个好人](https://www.xiaoyuzhoufm.com/episode/6a08e1b6e1eb34a9398856a6)
+
### 看好你的硬件
> [!note] 📜
@@ -28,6 +33,122 @@ toc = true
就算不相信这样的未来即将到来,「Buy it for life」的思想也是值得学习的。即便消费者文化持续,也不代表所有人都要参与到这种文化当中。
+### 框架的假象
+
+> [!note] 📜
+> [The framework mirage](https://numergent.com/2016-06/The-framework-mirage.html)
+
+*所以 Planet Clojure 为什么会把一篇十年前的文章推送到 Feed 里?*
+
+这篇文章先描述了这种困境:如果你使用框架编写 Web 应用,一开始可能会感到非常顺手,CRUD 以及各种基本操作非常省心,但投入很多时间精力过后,可能会发现框架的部分功能并不称心如意,这个时候提交问题可能并不会得到结果(比如开发者认为这不在框架的问题范围之内),这个时候你的选择要么是抛弃这个框架重写,要么是 Fork 这个框架自己添加想要的功能,但都很耗时耗力。
+
+然后作者介绍了 [Luminus](https://luminusweb.com/),一个轻量级的 Clojure Web 框架。这个框架的特点是,它需要你自己做很多决策,比如用什么数据库,引入什么第三方库,此外,脚手架一旦搭好,Luminus 的未来更新完全不会影响你的代码,除非你主动选择。
+
+看起来不错,但我想,使用任何一种框架,最核心的业务逻辑都应该是高度抽象的,不应该依赖底层细节,而框架提供的 CRUD 等能力明显是底层细节。如果开发者被框架困住,我想他需要审视一下自己的架构决策,让业务逻辑直接依赖框架是非常糟糕的。迁移框架当然要费不少精力,但绝非「必须重写」那么巨大。
+
+举个例子:
+
+![Framework <- Middle Man -> Service <-- ServiceImpl](https://img.eltr.ac/geedeapro/weekly/82/framework-middleman.jpg "如果 ServiceImpl 让你想起 Java 开发,请见谅,这的确是更好的设计")
+{.dark:invert}
+
+上述箭头描述的是依赖关系,空心箭头表示实现接口。简单来说,有一个中间人(Middle Man)了解如何调用框架和包含业务逻辑的服务类,这样业务逻辑就不需要直接依赖框架了。如果后续需要更换框架,只需要重写中间人,业务逻辑无需修改。
+
+同时要注意 `Service` 是高度抽象的,不依赖任何其他组件,如果需要调用别的具体实现,应该写在 `ServiceImpl` 实现类里,这样就保证了业务逻辑足够抽象,不依赖不应该依赖的东西(接口隔离原则),也保证业务逻辑不需要经常修改,有需求变动时只需要拓展或更换实现类(开闭原则)。
+
+### 用 Lua 写 HTML 模板可能很酷
+
+> [!note] 📜
+> [Lua can be a really cool HTML templating engine](https://riki.house/lua-html)
+
+作者先对比了 [Handlebars](https://handlebarsjs.com/) 和 Go 的 [html/template](https://pkg.go.dev/text/template) 库,两者是相似的 HTML 模板引擎,都允许用户在 HTML 模板里用类似 `{{ }}` 的语法插值,编写简单的赋值语句、循环结构和条件结构等等。不过 Go 的库要比前者(Rust 实现)更小巧,功能也差不多,在某些设计上也更讨喜(比如 Handlebars 有可怖的三括号语法 `{{{ }}}`,~~Lisp 程序员看了都摇头~~)。
+
+后来作者发现了 [Maud](https://maud.lambda.xyz/)(Rust 的宏),可以用这种格式写 HTML:
+
+```rust
+html! {
+ h1 { "Hello, world!" }
+ p.intro {
+ "This is an example of the "
+ a href="https://github.com/lambda-fairy/maud" { "Maud" }
+ " template language."
+ }
+}
+```
+
+看起来简洁得多,但实现很复杂,这个宏有 3000 行左右的代码,作者不喜欢。而 Lua 这边能使用十分简洁的原生语法,实现类似的效果,这归功于 Lua 优雅的语法设计,在函数只有一个参数时可以省略括号(比如 `print("a")` 可以写成 `print "a"`),如果这一个参数是数组或映射(Lua 的 `table`),就可以在不写圆括号的情况下,用花括号写入数组或映射的值。
+
+如果用 Lua 的函数作为 HTML 标签的表示,就可以得到如下的结构。
+
+```lua
+h.Document{
+ lang = "en",
+
+ h.head{
+ h.meta{charset = "UTF-8"},
+ h.title{"Hello, world!"},
+ },
+
+ h.body{
+ h.h1{"Hello, world!"},
+ h.p{
+ "This is an example of the little HTML templating framework I wrote ",
+ "in Lua in like 20 minutes."
+ },
+ h.p{
+ "As you can see, it is fully capable of generating any kind of markup ",
+ "you'd ever want.", h.br(),
+ "It can even do things like ", h.b"bold text", "!"
+ },
+ h.p"This is some embedded HTML <p></p>"
+ h.img{
+ alt = "riki sitting in pink space",
+ src = "https://riki.house/static/character/riki/sitting.png",
+ width = 2223, height = 1796,
+ style = "width: 20%; height: auto;"
+ },
+ },
+}
+```
+
+另一个好处在于,由于是直接用一门编程语言写的模板,只要利用语言本身的变量、字符串拼接、循环和分支结构,就不需要实现类似 `{{ }}` 的语法了。据我所知,Lua 本身也十分小巧,很容易嵌入其他语言编写的程序当中,就算不用 Lua 写博客程序,也可以专门嵌入在程序里做模板引擎。
+
+好了,写到这里我终于憋不住了:*Lisp can be the coolest HTML templating engine!*
+
+```clojure
+[:html
+ [:head
+ [:title "Eltrac"]
+ [:meta {:charset "utf-8"}]
+ [:meta {:name "viewport" :content "width=device-width,initial-scale=1"}]]
+ [:body
+ [:main.i-am-a-class#id
+ [:p "Be cool. Use Clojure."]]]]
+```
+
+上面是 Clojure 的 [Hiccup](https://github.com/weavejester/hiccup) 库,不少其他的 Lisp 方言也有类似的库,因为用 S-expression 编写 HTML 非常自然且简洁。[Spineret](https://github.com/ruricolist/spinneret)(Common Lisp 库)的写法与 Hiccup 类似,但只有圆括号:
+
+```lisp
+(defmacro with-page ((&key title) &body body)
+ `(with-html
+ (:doctype)
+ (:html
+ (:head
+ (:title ,title))
+ (:body ,@body))))
+
+(defun shopping-list ()
+ (with-page (:title "Home page")
+ (:header
+ (:h1 "Home page"))
+ (:section
+ ("~A, here is *your* shopping list: " *user-name*)
+ (:ol (dolist (item *shopping-list*)
+ (:li (1+ (random 10)) item))))
+ (:footer ("Last login: ~A" *last-login*))))
+```
+
+你看到那几个优雅得要命的宏了吗?
+
### Lisp 设计模式
> [!note] 📜