自建博客的技术分享,并浅谈由此接触的产品设计哲学

2026-02-21 · Alvin

frontendbackendproduct design

前言

本文更偏向于建站过程中的经历分享和技术唠嗑,而非建站教程。主要聊聊建站过程中我所产生的新的认识。对咱工科学生来说,实践永远是最好的老师。只有自己尝试了,才能深入了解业界生态,将所学转化为自己的本领。

站点技术选型和系统设计

框架认识和选择

本着尝试实践一些视觉上比较炫酷的好奇心理,站点实现的初步想法是选一个具有足够丰富生态的前端框架和成熟的后端服务。在经过一番调研后,我选择了 React 库及其应用层框架Next.js作为前端的骨架,后端则采用 Go 语言进行实现。

前端的应用框架层出不穷,最开始认识时我经常犯糊涂。早些年作为小白的我翻阅一些前端技术博客,一会一个jQuery,一会一个Vue,语言还分ts和js,名词是越来越多,看的是越看越懵。为了理清这些名词,我们可以将前端技术栈由底向上划分为四个关键层级

基础设施 -> UI组件库 -> 应用层框架 -> 工程化工具链

  • 基础设施与语言层(The Foundation):最底层的原材料,包括 HTML、CSS 和 JavaScript/TypeScript。TypeScript 作为 JS 的超集,在现代工业开发中已成为标准,通过静态类型检查规避了大量低级错误。
  • UI 库与组件层(UI Library):React 所在的层级。它不再让我们直接操作网页的“砖块”(DOM),而是提供了一套高度组件化的“模具”。DOM 是浏览器将 HTML 转换为可操作对象的树状结构。早期的前端开发(如 jQuery 时代)是直接操纵 DOM。而 React 则通过虚拟DOM,让我们只需要操作轻量级 JS 对象。我们只需要定义好数据的状态,React 就会自动完成视图的更新。
  • 应用框架层(App Framework):在组件库基础上,集成路由管理、服务器端渲染(SSR)和构建优化的框架。Next.js就是React对应的应用层架构,解决了React单纯作为库无法处理的 SEO 和首屏加载性能问题。与之相应的“孪生双胞胎”Nuxt.js,则对应Vue组件库。Vue以极其平滑的学习曲线著称,在中国开发者群体中拥有极高的市场份额。同时还有一些为静态内容而生的框架,如Astro,Hugo等。
  • 工程化与工具链(Tooling):包括 Vite、Webpack 以及包管理器(npm/pnpm),负责将我们写的各种碎片化代码压缩、打包,最终转化为浏览器能高效运行的产物。

从工业化角度看React + Go体系,选择 React 绝不仅仅是选择一个库,而是选择了全球最大的前端生态。这意味着无论遇到什么诡异的 UI 需求,你都能找到现成的组件库(如 Ant Design 或 Tailwind CSS)以及成熟的调试工具。对于开发者而言,React 的 Hooks 机制和最近推出的 React Compiler,极大地降低了维护复杂交互逻辑的成本,使前端开发从“手工艺术”转向了“精密组装”。后端选择 Go 语言,则是看中了其天然的并发处理能力和极高的执行效率。Go 的语法极其精简,没有复杂的继承体系,这种“工业级”的克制使得代码非常易于阅读和维护。其生成的二进制文件部署极其简单,对于追求高性能 API 和稳定微服务的场景来说,Go 是不二之选。

系统功能设计

技术选型选好了,接下来便是功能落地和代码实现。博客功能大差不差,基本也就展示自己的学习经验和项目。或许有人说,现在Agent代码生成这么成熟了,让AI生成一个不就完了吗。此言差矣,博客是个人风格的体现,我如何能确保AI生成的东西是我想要的?Agent确实强大,但AI实现我需求的前提,是我能将需求精准的提给Agent。且Agent缺乏良好prompt的情况下很容易重复造轮子,让代码架构变得混乱。因此,为了让Agent能生成我满意的代码,实现一个足够美观的程序,我需要解决两个问题:业界标准的代码组织架构和我博客的个人使用习惯

在代码组织架构上,我参考了我在小厂实习的经验,前端使用标准Restful API接口风格,使用单独的api路由代理。后端使用Uber/fx的依赖注入架构,使用gin网络框架和gorm自动生成数据库字段,让功能代码高度模块化。Agent生成代码时,将严格依照以上原则。感兴趣的朋友可移步github阅读代码。

var serveCmd = &cobra.Command{
	Use:   "serve",
	Short: "start the blog backend server",
	Run: func(cmd *cobra.Command, args []string) {
		app := fx.New(
			// Provide the config file path to the DI container.
			fx.Provide(func() string { return configFile }),
			config.Module,
			resource.Module,
			blog.Module,
			system.Module,
			server.Module,
			fx.Invoke(func(cfg *config.Config) {
				log.Println("🐋 Whalefall Blog Server Started")
				log.Printf("   Environment : %s", cfg.App.Environment)
				log.Printf("   Go Version  : %s", GoVersion)
				log.Printf("   Listening   : %s:%d", cfg.Server.Host, cfg.Server.Port)
			}),
		)
		app.Run()
	},
}

针对我个人的使用习惯,我并非将博客内容作为静态数据放在前端编译,也并非将博客放在更不好修改内容的后端数据库。为了博客更新与发布的便利性,让我能一劳永逸。我参考了**Headless CMS(无头内容管理)**的思想,让后端只存放博客标题,发布时间等元数据,当前端发起博客详情请求时,后端再从文件系统读取。为此我单独写了一个后端元数据管理的命令行工具,写完博客后,我能命令行一键发布,而针对博客内容的修改,保存后前端一键刷新就能看到。这样的架构即便部署到服务器,也能利用CI/CD完成博客发布,对我这个懒人来说,还是自动化流程看的比较顺眼。

我和UI斗争的那些事

探索设计的开始

设计自己的博客好比开创一个自己的小天地,在自己的bubbles里能放任自己天马行空的想法。最开始我看到觉得好的设计就想加进页面,一股脑的堆砌元素。想加一个landing动画,想加一个自定义滚动条等等,但我发现堆砌之后往往只有一片混乱,这不仅增加了代码工作量,复杂的设计让我难以和Agent一同维护代码,也掩盖了我分享内容的初衷。

为了能更清晰的呈现自己的内容,同时保留一定的设计感,我便开始有目的性的参考别人的博客设计。将我想提供的博客功能简化为概念对应四个导航栏tab。出于内容优先的原则,将博客列表放在左侧,以符合人们日程的阅读习惯。为了搜索功能的便捷,添加tag搜索功能和对应的UI组件。从结果上来说,或许最终产生的页面结构与别人大同小异,但从想法设计到实际落地过程中的思考非常有意思。

古往今来的设计哲学

Cursor设计负责人Ryo在一次访谈中的观点,让我产生了很多共鸣。

像素已死,系统永生:与Cursor设计负责人Ryo聊builder时代的到来

从中可以窥得现有系统界面设计发展历程的一角:我们从现实世界提取概念对应操作系统,来让普通人感知数字世界,让计算机得以普及。在用户熟悉概念并形成使用习惯后,大家已经具有相同的共识,Apple进一步遵循用户共识,简化了系统设计,也成功的推广了移动端设备,可以说是一个跨越时代的胜利。软件的初衷便是完成用户需求,而设计则是在使用体验与目标需求之间进行平衡。如今AI的加入,更进一步的影响了设计范式。

软件能成为你想看到的样子,本质上它是同一个东西,但不同的人使用,具有不同的展开方式和路径。

AI所带来的设计上生产力的爆发,让团队具有更多的余力打磨他们的软件,也让团队有能力为用户呈现更多方案。在开发流程上,Agent为所有人提供了coding能力,设计者和工程师能面对同一个context,同一个code base,各自从不同的视角切入,来完成一个项目。这极大的提升了团队在市场的竞争力。

未来系统设计的幻想

从designer到builder,Agent工具不仅大幅度降低了不同行业不同概念间理解的门槛,也为个性化的设计和服务带来了巨大的潜力。我们不妨想象系统的模样,它更加简洁:界面即界面,服务即服务,数据即数据。正如我在博客系统中将文本数据与博客的后端元数据分离那样,当我想关注于博客文本时,我能直接修改文本数据而避免冗余的推送步骤,而不用关心其他。

我不曾一次苦恼过,为什么我不能手机打开代码的IDE,为什么不能将我所有的数据建立数据中心,让我所有设备都可以访问?或许传统工业体系下实现这么一个系统会带来难以估量的成本,但在 Agent 时代,我们是否可以幻想一种“数据即主权”的可能性?开发者不再受限于特定的 IDE,用户不再受限于特定的 UI。正如我这个简陋的博客系统,通过元数据与内容的解耦,实现了一种极其微小的“自由”。让我们一起期待,AI 将如何把我们从琐碎的像素对齐中解放出来,去构建真正属于未来的“数字永生系统”。