博客功能计划(永久更新)

前言


这是一个从 2019 年 10 月份开始的新项目,是我网络历史生涯上线的第三个博客。也是目前最新的、抱以最大期待的博客程序。关于前两个,可以看博客的说明和历史介绍

同时这也是一个开源项目,右上角那个 GitHub 图标的链接便是仓库地址。并且在未来很长一段时间里,它都会存在。

为此,我用一篇文章来整理关于博客功能的开发计划,也是对博客本质功能的一种体现。并且这份计划对于以后潜在的本博客程序的用户而言,就是更新日志。这便是本文存在的理由。

设计原则


本项目有一些原则来进行保证,它们是提前考虑好的。这些提前“思考”可以避免在开发过程中迷失方向、减少对功能的思考过程、规避破坏性修改,从而提高兼容性。

本博客基于这些原则进行设计

  • 永远以最本质的功能为主,仅包括浏览文章列表阅读文章
  • 尝试更先进或感兴趣的技术,但不能忽略对搜索引擎的优化(SEO)。
  • 移动优先。特别是对于前台页面,必须保持对手机的良好阅读体验。
  • 简约、快速,绝不显得沉重和冗余。

不出意外的话,以上原则直到这个项目停滞甚至死亡都会遵守。这些同时也限制了它永远不会是一个庞大、通用的 CMS,定制性也并非重点。这对于考虑部署自己博客人而言,可能都是减份项。所以实际上我并不想有人部署这个程序,因为我的目标是让它成为一个「参考」,无论是技术上还是功能设计上。

附加:正如你所看到的,评论并未包含在本质功能中。但是这不表示不会有评论功能,它很快就会添加,只是我还需要一些思考和开发时间。

核心元素


  1. 文章:博客的内容来源
  2. 类别:对文章的归类
  3. 标签:文章所包含的关键字列表

以上三者是最本质的内容元素,除此之外没有任何东西是不可或缺的。这些核心元素的列表显示、查询和内容之间的组合,构成了本博客的核心功能。

附加功能


基于上述核心元素,也产生了一些用以改善阅读、搜索或 SEO 体验的附加功能。下面是对它们的一些介绍。

SLUG 重定向

本博客的所有核心元素在前台都是通过 SLUG 而不是 ID 获取的。举个典型的例子,著名问答社区 Quora 上所有提问的链接是基于标题“转换”而来的,并非“数字”或看不懂的一串“乱码”,它们是语义化的。

所谓「转换」也就是将标题进行格式化,符合 SLUG 的原则。「数字」指的是常见的数据库自增 ID,而「乱码」无非就是 UUID 或某种 HASH,它们是一些常见或不常见的数据库主键策略。对于数据库而言,主键的优势远远大于非主键的自定义 SLUG 字段,但是对于访问内容而言,这些主键策略是枯燥无趣、毫无意义的。而语义化的 SLUG 是「人类可读」并且有 SEO 加成的。简单的说:在内部 ID 优势大,在外部(表面)SLUG 更好

为什么本博客选择了 SLUG 而不是数据 ID?因为我一向都认为 SLUG 很好,人类可读的链接很好,仅此而已。

上面提到过 SLUG 对数据库而言可能不如主键,这主要是性能和安全性方面的劣势。例如主键自带索引和约束,不用花心思优化。但是对于区区博客这样的小型 Web 应用而言,带来的影响是微乎其微的,甚至不需要你去特意优化基于 SLUG 的性能。

SLUG 真正的劣势

SLUG 相对于 ID 真正的劣势在于「不可预估的链接有效期」。这是什么意思呢?就是说基于 ID 的链接是持久性的,除非数据被删除,除此之外没有不可预估的情况会导致内容获取不到。但基于 SLUG 的链接,因为 SLUG 是可变的,那样即便内容还存在,若 SLUG 产生变化,以往的链接便都失效了。

举个例子,GitHub 上的仓库链接格式为:https://github.com/<Username>/<Reponame>。如果你的用户名或仓库名称变了,那么这个链接就失效了。这可能会带来很严重的后果,如果一个比较著名或重要的项目其链接一定会被在大量第三方内容中索引,如果这些链接都失效了,那是很可怕的。
虽然一般来讲,用户名基本不会变或变化机率(或频率)极低,但是仓库名称是有很可能变化的。据我所知道的,很多知名项目都有改名的经历,更何况一些项目初步根本没有想好名字(例如本博客的项目就是 Hentioe/blog)。项目也可能发生位置变化,例如从个人转移到组织下。可变的 SLUG 带来了不可预估的链接有效期,这才是最大的缺点。

解决 SLUG 的问题

如果你是一个经常逛 GitHub 的人,恐怕一开始就明白 SLUG 重定向指的是什么了。没错,GitHub 并不存在上述问题,因为你无论怎样改名,GitHub 始终能让旧有链接重定向到最新的链接上。例如项目原本在 Hentioe/blog 后来转移到组织下面了,变成了 bluerain.io/blog。即便如此,访问 Hentioe/blog 也能自动重定向到 bluerain.io/blog 上,这便是重定向对于 SLUG 的重要性。

本博客文章的 SLUG 一旦产生变化,就会自动添加一条重定向映射的记录,无论文章变化多少次,产生了多少个不一样的链接,它们永久有效,永远会重定向到最新的链接上。

我必须要开发这项功能,因为我曾经的博客的部分文章在 Google 有高权重的索引,未来我会逐步迁移旧有文章过来,手动添加重定向映射,让那些搜索结果链接“死而复生”。

2019-11-03:此功能还未实现。
2019-11-07:此功能已实现。

日期归类标签

很多博客程序会自动将文章归类到例如「2019 年 01 月」「……2 月」这些基于月份或年份的日期分类中。老实讲我并没有研究过这些归类是属于什么,究竟是一种「类别」还是一个「标签」,或者是一个独立的日期文件夹?毕竟那些博客程序很多访问文章的链接中都要包含年份和月份(这在我看来完全没有必要)。

对于本博客而言,日期归类是一种「特殊的标签」。它们仍然是标签,可以被文章包含多个,也可以包含多个文章,这种本质关系没有改变。当文章发表之时,会生成(或查找已存在的)日期归类标签并自动关联上。因为日期归类标签是特殊的,所以它可以不跟普通标签混在一起显示在首页中(或者独立显示日期归类列表)。又因为标签也是过滤文章的条件之一,所以日期归类标签也有「日期文件夹」的作用。

2019-11-03:此功能还未实现。

计数器

计数指的是对例如阅读次数、某分类的文章数量,评论数量或点赞次数等数据的统计。它们并没有和原始数据表字段耦合在一起,主要原因跟可见性有关。如果我将一篇文章放入回收站,因为我没有删除这篇文章,那么分类表应该怎么更新其关联文章数量呢?是更新为前台可见的(数量少一)还是后台可见(数量不变)呢?当然你的确可以不进行计数储存,直接根据条件即时查询出来,但那样性能太差,如果几十数百个标签都要统计文章数量,那访问一次就得进行几百次统计查询了。

所以,最好的方式是将计数独立出来。本博客的计数在前后台显示是不一致的,适应了不同的可见性。通过嵌入式 KV 数据库分别缓存统计后的不同可见性下的计数,并在最终同步到关系形数据库中的计数表持久化储存。所以本博客的计数器有很高的性能,且能在不同可见性的条件下区别显示。

补充:物尽其用,此嵌入式 KV 数据库是利用 Mnesia 实现的。虽然是嵌入式,但 Mnesia 并不会对集群部署造成麻烦,因为它支持多节点。所以我并不需要部署一个 Redis 去做类似的事情。

2019-11-03:此功能还未实现。
2019-11-08:此功能已实现。

站点地图

为了确保 Google 或其它搜索引擎对本博客内容抓取的实时性,博客提供了站点地图。注意,站点地图并非动态内容,而是定时生成的静态文件。

一般来讲,站点地图都是静态文件,因为它包含了一个网站的几乎所有前台可见链接。假若知乎要生成站点地图,会将所有问题的链接加入进去,生成的文件体积大并且零散(拆分成数个地图文件)。如果说动态生成,每访问一次就查询出所有问题数据,然后动态渲染出地图结构,那当然是不现实的。

除非你的站点地图内容非常小,无论怎样访问都不会对性能和生成速度产生影响,就好像载入一次首页或查看一次文章列表一般轻松。说实话,对于个人博客而言确实可以这样做,毕竟一个人能写多少文章呢?

不过我一直很抵触这种怎么简单怎么来的不常规做法,所以我没有让站点地图也成为动态内容,而是定时生成静态地图。即便某天博客允许其它人投稿了,甚至产生了成千上万的文章,都不存在前期的“技术债务”。这是我不会因为简单却可用就会考虑的主要原因。

2019-11-10:此功正在实现。

本文还在逐步更新中……

关于本文