Compare commits

..
4 Commits
Author SHA1 Message Date
ascoders b1a43d4843 update readme 2022-02-28 08:44:55 +08:00
ascoders 9cb731cb36 231 2022-02-28 08:43:47 +08:00
ascoders 93828e08b2 230 2022-02-28 08:38:01 +08:00
ascoders 0b06c714fa 230 2022-02-21 09:57:08 +08:00
5 changed files with 327 additions and 2 deletions
+174
View File
@@ -0,0 +1,174 @@
本系列是 SQL 系列的开篇,介绍一些宏观与基础的内容。
## SQL 是什么?
SQL 是一种结构化查询语言,用于管理关系型数据库,我们 90% 接触的都是查询语法,但其实它包含完整的增删改查和事物处理功能。
## 声明式特性
SQL 属于声明式编程语言,而现代通用编程语言一般都是命令式的。但是不要盲目崇拜声明式语言,比如说它未来会代替低级的命令式语言,因为声明式本身也有它的缺点,它与命令式语言也有相通的地方。
为什么我们觉得声明式编程语言更高级?因为声明式语言抽象程度更高,比如 `select * from table1` 仅描述了要从 table1 查询数据,但查询的具体步骤的完全没提,这背后可能存在复杂的索引优化与锁机制,但我们都无需关心,这简直是编程的最高境界。
那为什么现在所有通用业务代码都是命令式呢?因为 **命令式给了我们描述具体实现的机会** ,而通用领域的编程正需要建立在严谨的实现细节上。比如校验用户权限这件事,即便 AI 编程提供了将 “登陆用户仅能访问有权限的资源” 转化为代码的能力,我们也不清楚资源具体指哪些,以及在权限转移过程中的资源所有权属于谁。
SQL 之所以能保留声明式特性,完全因为锁定了关系型数据管理这个特定领域,而恰恰对这个领域的需求是标准化且可枚举的,才使声明式成为可能。
基于命令式语言也完全可拓展出声明式能力,比如许多 ORM 提供了类似 `select({}).from({}).where({})` 之类的语法,甚至一个 `login()` 函数也是声明式编程的体现,因为调用者无需关心是如何登陆的,总之调用一下就完成了登陆,这不就是声明式的全部精髓吗?
## 语法分类
作为关系型数据库管理工具,SQL 需要定义、操纵与控制数据。
数据定义即修改数据库与表级别结构,这些是数据结构,或者是数据元信息,它不代表具体数据,但描述数据的属性。
数据操纵即修改一行行具体数据,增删改查。
数据控制即对事务、用户权限的管理与控制。
### 数据定义
DDLData Definition Language)数据定义,包括 `CREATE` `DROP` `ALTER` 方法。
### 数据操纵
DMLData Manipulation Language)数据操纵,包括 `SELECT` `INSERT` `UPDATE` `DELETE` 方法。
### 数据控制
DCLData Control Language)数据控制,包括 `COMMIT``ROLLBACK` 等。
所有 SQL 操作都围绕这三种类型,其中数据操纵几乎占了 90% 的代码量,毕竟数据查询的诉求远大于写,数据写入对应数据采集,而数据查询对应数据分析,数据分析领域能玩出的花样远比数据采集要多。
PS:有些情况下,会把最重要的 `SELECT` 提到 DQLData Query Language)分类下,这样分类就变成了四个。
## 集合运算
SQL 世界的第一公民是集合,就像 JAVA 世界第一公民是对象。我们只有以集合的视角看待 SQL,才能更好的理解它。
何为集合视角,即所有的查询、操作都是二维数据结构中进行的,而非小学算术里的单个数字间加减乘除关系。
集合的运算一般有 `UNION` 并集、`EXCEPT` 差集、`INTERSECT` 交集,这些都是以行为单位的操作,而各种 JOIN 语句则是以列为单位的集合运算,也是后面提到的连接查询。
只要站在二维数据结构中进行思考,运算无非是横向或纵向的操作。
## 数据范式
数据范式分为五层,每层要求都比上一层更严苛,因此是一个可以逐步遵循的范式。数据范式要求数据越来越解耦,减少冗余。
比如第一范式要求每列都具有原子性,即都是不可分割的最小数据单元。如果数据采集时,某一列作为字符串存储,并且以 "|" 分割表示省市区,那么它就不具有原子性。
当然实际生产过程往往不都遵循这种标准,因为表不是孤立的,在数据处理流中,可能在某个环节再把列原子化,而原始数据为了压缩体积,进行列合并处理。
希望违反范式的还不仅是底层表,现在大数据处理场景下,越来越多的业务采用大宽表结构,甚至故意进行数据冗余以提升查询效率,列存储引擎就是针对这种场景设计的,所以数据范式在大数据场景下是可以变通的,但依然值得学习。
## 聚合
当采用 GROUP BY 分组聚合数据时,如希望针对聚合值筛选,就不能用 WHERE 限定条件了,因为 WHERE 是基于行的筛选,而不是针对组合的。(GROUP BY 对数据进行分组,我们称这些组为 “组合”),所以需要使用针对组合的筛选语句 HAVING:
```sql
SELECT SUM(pv) FROM table
GROUP BY city
HAVING AVG(uv) > 100
```
这个例子中,如果 HAVING 换成 WHERE 就没有意义,因为 WHERE 加聚合条件时,需要对所有数据进行合并,不符合当前视图的详细级别。(关于视图详细级别,在我之前写的 [精读《什么是 LOD 表达式》](https://github.com/ascoders/weekly/blob/master/%E5%89%8D%E6%B2%BF%E6%8A%80%E6%9C%AF/215.%E7%B2%BE%E8%AF%BB%E3%80%8A%E4%BB%80%E4%B9%88%E6%98%AF%20LOD%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E3%80%8B.md) 有详细说明)。
聚合如此重要,是因为我们分析数据必须在高 LEVEL 视角看,明细数据是看不出趋势的。而复杂的需求往往伴随着带有聚合的筛选条件,明白 SQL 是如何支持的非常重要。
## CASE 表达式
CASE 表达式分为简单与搜索 CASE 表达式,简单表达式:
```sql
SELECT CASE pv WHEN 1 THEN 'low' ELSE 'high' END AS quality
```
上面的例子利用 CASE 简单表达式形成了一个新字段,这种模式等于生成了业务自定义临时字段,在对当前表进行数据加工时非常有用。搜索 CASE 表达式能力完全覆盖简单 CASE 表达式:
```sql
SELECT CASE WHEN pv < 100 THEN 'low' ELSE 'high' END AS quality
```
可以看到,搜索 CASE 表达式可以用 “表达式” 描述条件,可以轻松完成更复杂的任务,甚至可以在表达式里使用子查询、聚合等手段,这些都是高手写 SQL 的惯用技巧,所以 CASE 表达式非常值得深入学习。
## 复杂查询
SELECT 是 SQL 最复杂的部分,其中就包含三种复杂查询模式,分别是连接查询与子查询。
### 连接查询
指 JOIN 查询,比如 LEFT JOIN、RIGHT JOIN、INNER JOIN。
在介绍聚合时我们提到了,连接查询本质上就是对列进行拓展,而两个表之间不会无缘无故合成一个,所以必须有一个外键作为关系纽带:
```sql
SELECT A.pv, B.uv
FROM table1 as t1 LEFT JOIN table2 AS P t2
ON t1.productId = t2.productId
```
连接查询不仅拓展了列,还会随之拓展行,而拓展方式与连接的查询的类型有关。除了连接查询别的表,还可以连接查询自己,比如:
```sql
SELECT t1.pv AS pv1, P2.pv AS pv2
FROM tt t1, tt t2
```
这种子连接查询结果就是自己对自己的笛卡尔积,可通过 WHERE 筛选去重,后面会有文章专门介绍。
### 子查询与视图
子查询就是 SELECT 里套 SELECT,一般来说 SELECT 会从内到外执行,只有在关联子查询模式下,才会从外到内执行。
而如果把子查询保存下来,就是一个视图,这个视图并不是实体表,所以很灵活,且数据会随着原始表数据而变化:
```sql
CREATE VIEW countryGDP (country, gdp)
AS
SELECT country, SUM(gdp)
FROM tt
GROUP BY country
```
之后 `countryGDP` 这个视图就可以作为临时表来用了。
这种模式其实有点违背 SQL 声明式的特点,因为定义视图类似于定义变量,如果继续写下去,势必会形成一定命令式思维逻辑,但这是无法避免的。
## 事务
当 SQL 执行一连串操作时,难免遇到不执行完就会出现脏数据的问题,所以事务可以保证操作的原子性。一般来说每个 DML 操作都是一个内置事务,而 SQL 提供的 START TRANSACTION 就是让我们可以自定义事务范围,使一连串业务操作都可以包装在一起,成为一个原子性操作。
对 SQL 来说,原子性操作是非常安全的,即失败了不会留下任何痕迹,成功了会全部成功,不会存在中间态。
## OLAP
OLAPOnLine Analytical Processing)即实时数据分析,是 BI 工具背后计算引擎实现的基础。
现在越来越多的 SQL 数据库支持了窗口函数实现,用于实现业务上的 runningSum 或 runningAvg 等功能,这些都是数据分析中很常见的。
以 runningSum 为例,比如双十一实时表的数据是以分钟为单位的实时 GMV,而我们要做一张累计到当前时间的 GMV 汇总折线图,Y 轴就需要支持 `running_sum(GMV)` 这样的表达式,而这背后可能就是通过窗口函数实现的。
当然也不是所有业务函数都由 SQL 直接提供,业务层仍需实现大量内存函数,在 JAVA 层计算,这其中一部分是需要下推到 SQL 执行的,只有内存函数与下推函数结合在一起,才能形成我们在 BI 工具看到的复杂计算字段效果。
## 总结
SQL 是一种声明式语言,一个看似简单的查询语句,在引擎层往往对应着复杂的实现,这就是 SQL 为何如此重要却又如此普及的原因。
虽然 SQL 容易上手,但要系统的理解它,还得从结构化数据与集合的概念开始进行思想转变。
不要小看 CASE 语法,它不仅与容易与编程语言的 CASE 语法产生混淆,本身结合表达式进行条件分支判断,是许多数据分析师在日常工作中最长用的套路。
现在使用简单 SQL 创建应用的场景越来越少了,但 BI 场景下,基于 SQL 的增强表达式场景越来越多了,本系列我就是以理解 BI 场景下查询表达式为目标创建的,希望能够学以致用。
> 讨论地址是:[精读《SQL 入门》· Issue #398 · ascoders/weekly](https://github.com/ascoders/weekly/issues/398)
**如果你想参与讨论,请 [点击这里](https://github.com/ascoders/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**
> 关注 **前端精读微信公众号**
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)
+1
View File
@@ -12,6 +12,7 @@ const dirs = [
"源码解读",
"商业思考",
"算法",
"SQL"
];
dirs.forEach((dir) => {
+9 -2
View File
@@ -6,7 +6,7 @@
前端界的好文精读,每周更新!
最新精读:<a href="./前沿技术/229.%E7%B2%BE%E8%AF%BB%E3%80%8Avue-lit%20%E6%BA%90%E7%A0%81%E3%80%8B.md">229.精读《vue-lit 源码》</a>
最新精读:<a href="./SQL/231.SQL%20%E5%85%A5%E9%97%A8.md">231.SQL 入门</a>
素材来源:[周刊参考池](https://github.com/ascoders/weekly/issues/2)
@@ -19,6 +19,8 @@
### 前沿技术
### 前沿技术
- <a href="./前沿技术/1.%E7%B2%BE%E8%AF%BB%E3%80%8Ajs%20%E6%A8%A1%E5%9D%97%E5%8C%96%E5%8F%91%E5%B1%95%E3%80%8B.md">1.精读《js 模块化发展》</a>
- <a href="./前沿技术/2.%E7%B2%BE%E8%AF%BB%E3%80%8A%E6%A8%A1%E6%80%81%E6%A1%86%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E3%80%8B.md">2.精读《模态框的最佳实践》</a>
- <a href="./前沿技术/3.%E7%B2%BE%E8%AF%BB%E3%80%8A%E5%89%8D%E5%90%8E%E7%AB%AF%E6%B8%B2%E6%9F%93%E4%B9%8B%E4%BA%89%E3%80%8B.md">3.精读《前后端渲染之争》</a>
@@ -185,7 +187,7 @@
- <a href="./前沿技术/225.%E7%B2%BE%E8%AF%BB%E3%80%8AExcel%20JS%20API%E3%80%8B.md">225.精读《Excel JS API》</a>
- <a href="./前沿技术/226.%E7%B2%BE%E8%AF%BB%E3%80%8A2021%20%E5%89%8D%E7%AB%AF%E6%96%B0%E7%A7%80%E5%9B%9E%E9%A1%BE%E3%80%8B.md">226.精读《2021 前端新秀回顾》</a>
- <a href="./前沿技术/228.%E7%B2%BE%E8%AF%BB%E3%80%8Apipe%20operator%20for%20JavaScript%E3%80%8B.md">228.精读《pipe operator for JavaScript》</a>
- <a href="./前沿技术/229.%E7%B2%BE%E8%AF%BB%E3%80%8Avue-lit%20%E6%BA%90%E7%A0%81%E3%80%8B.md">229.精读《vue-lit 源码》</a>
- <a href="./前沿技术/230.%E7%B2%BE%E8%AF%BB%E3%80%8A%E5%AF%B9%20Markdown%20%E7%9A%84%E6%80%9D%E8%80%83%E3%80%8B.md">230.精读《对 Markdown 的思考》</a>
### 设计模式
@@ -241,6 +243,7 @@
- <a href="./源码解读/155.%20%E7%B2%BE%E8%AF%BB%E3%80%8Ause-what-changed%20%E6%BA%90%E7%A0%81%E3%80%8B.md">155. 精读《use-what-changed 源码》</a>
- <a href="./源码解读/156.%20%E7%B2%BE%E8%AF%BB%E3%80%8Areact-intersection-observer%20%E6%BA%90%E7%A0%81%E3%80%8B.md">156. 精读《react-intersection-observer 源码》</a>
- <a href="./源码解读/227.%20%E7%B2%BE%E8%AF%BB%E3%80%8Azustand%20%E6%BA%90%E7%A0%81%E3%80%8B.md">227. 精读《zustand 源码》</a>
- <a href="./源码解读/229.%E7%B2%BE%E8%AF%BB%E3%80%8Avue-lit%20%E6%BA%90%E7%A0%81%E3%80%8B.md">229.精读《vue-lit 源码》</a>
### 商业思考
@@ -264,6 +267,10 @@
- <a href="./算法/201.%E7%B2%BE%E8%AF%BB%E3%80%8A%E7%AE%97%E6%B3%95%20-%20%E4%BA%8C%E5%8F%89%E6%A0%91%E3%80%8B.md">201.精读《算法 - 二叉树》</a>
- <a href="./算法/203.%E7%B2%BE%E8%AF%BB%E3%80%8A%E7%AE%97%E6%B3%95%20-%20%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E3%80%8B.md">203.精读《算法 - 二叉搜索树》</a>
### SQL
- <a href="./SQL/231.SQL%20%E5%85%A5%E9%97%A8.md">231.SQL 入门</a>
## 关注前端精读微信公众号
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
@@ -0,0 +1,143 @@
Markdown 即便在 2022 年也非常常用,比如这篇文章依然采用 Markdown 编写。
但 Markdown 是否应该成为文本编辑领域的默认技术选型呢?答案是否定的。我找到了一篇批判无脑使用 Markdown 作为技术选型的好文 [Thoughts On Markdown](https://www.smashingmagazine.com/2022/02/thoughts-on-markdown/),它提到 Markdown 在标准化、结构化、组件化都存在硬伤,如果你真的想做一个现代化的文本结构编辑器,不要采用 Markdown。
## 概述
Markdown 流传甚广,甚至已成为我们的第二语言。Markdown 最早的解析器由 John Gruber 在 2004 年基于 Perl 编写发布,那时候 Markdown 只有一个目的,即为了方便网络写作。
网络写作必须基于 HTML 规范,而 HTML 规范对大部分人上手成本太高,因此 Markdown 就是基于文本创建的更易理解,或者说上手成本更低,甚至傻瓜化的一种语法,而要解析这个语法需要配套一个解析器,将这种语法文本最终转化为 HTML。
而数字化发展到今天,Markdown 已不再适合当下的写作场景了,主要原因有二:
1. Markdown 不再适合当下富交互、内容形态的编写。
2. Markdown 纯文本的开发体验不再满足当代开发者日益提高的体验需求。
首先还是从 Markdown 思想开始介绍。
### Markdown 的核心思想
Markdown 最大优势就是好上手,不需要接触 HTML 这种复杂的嵌套语句(虽然对程序员来说 HTML 也简单到处于鄙视链底端)。原文抽象了三个优势:
1. 基于文本的合适抽象。虽然 HTML 甚至代码都是文本,但 “合适” 这个词很重要,即任何文本都可以是 Markdown,只要加一点点小标记就能描述专业结构,学习成本极低。
2. 有大量生态工具。比如语法解析器、高亮、格式转换、格式化、渲染等工具完备。
3. 编辑内容便于维护。比如 Markdown 很方便作为源码存储,而其他格式的富文本可能并不方便在源码里维护。
如果把 Markdown 与数据库表结构做比较,那数据库的理解成本真是太高了。
但是在如今后端即服务的时代,数据库访问越来越轻松,甚至出现大量如 AirTable 等 SAAS 产品将结构化数据快速转化为应用,其实接触了这些后才真正发现,结构化数据对开发者有多重要。Markdown 用来写写文章还是不错的,但用来表达逻辑结构最后一定会引发灾难后果,原文作者的团队就深受 Markdown 技术选型的困扰,被迫解决大量远超预期的难题。
如果真的要在 Markdown 的坑越走越深,就必须使用语法拓展来满足自定义诉求。
### Markdown 语法拓展
最初 Markdown 语法是不支持表格的,如果想用 Markdown 绘制一张表格,只能使用原生 HTML 标签:`<tabke></table>`,当然,这也说明了 Markdown 本质就是给 HTML 加强了便捷的语法,我们完全可以将其当 HTML 使用。
然而并不是所有创作平台都支持 `<table></table>` 语法的,笔者自己就经常受到困扰,比如有些平台会屏蔽原生 HTML 语法,已保障所谓的 “安全性” 或者内容体验的 “一致性”,而这些平台为了弥补缺失的绘制表格能力,往往会支持一些自定义语法,更糟糕的是不支持,这就说到了 Markdown 的语法拓展。
Markdown 有哪些拓展呢?比如:[multiMarkdown](https://fletcherpenney.net/multimarkdown/)、[commonMark](https://commonmark.org/)、[Github Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github) 等等。
这里随便举个例子,比如标准 MD 格式,其实第一行最后要加两个空格才能换行,但 GFM 取消了这个限制。这虽然更方便了,但暴露出平台间规范的不一致性,导致 Markdown 跨平台基本一定被坑。
而各平台拓展的语法,我们是否有足够的精力学习和记忆呢?先不说能不能记得下来,首先值不值得学习就是个问题,为什么一个网络写作平台需要占用写手学习与认知成本,而不是想办法去简化写作流程呢?所以语法拓展看似很美好,但放在写手角度,或者整个互联网各平台林立的角度来看,这种非标准的做法一定不靠谱,没有用户觉得你的平台有资格 “教他语法”,除非你是微信,钉钉或者飞书。
原文提到的观点是:
1. 作为写手,你不知道 Markdown 哪些语法可用,哪些语法不可用。
2. 标准规范存在一些 [模糊地带](https://johnmacfarlane.net/babelmark2/faq.html#what-is-this-for) 导致开发者实现时也会遇到各种纠结。
原文还提到一个语法拓展导致理解成本增高的例子:slack 平台自定义的 [mrkdown](https://api.slack.com/reference/surfaces/formatting#basics) 就不支持 `[link](https://slack.com)` 方式描述链接,而使用了 `<link|https://slack.com>` 语法。
总结来说,Markdown 语法拓展本应该是件好事,但实际无标准导致了标准的百花齐放,使 Markdown 成为了实际上没有标准的状态,整体来看弊端更多。
### Markdown 面向的用户群
Markdown 的对自己的定位其实很不清晰,这也导致了一直不想确定标准化语法。
最初 Markdown 是服务给熟悉 HTML 的人提供的标记语言,而后来面向用户群实质上转向了开发者,因为开发者才会想到拓展语法以满足更复杂的使用场景,Markdown 原生语法无法适应越来越复杂的视觉展示形态。
如今 Markdown 的主要用户已经是开发人员与对代码感兴趣的人了,这倒不是说开发者有多喜欢它,而是在说 Markdown 的受众变窄了。如今任何一款面向非开发者群体的文档编辑器都不会采用 Markdown 了,而是所见即所得的 WYSIWYGwhat you see is what you want)模式。
这个转变的过程是痛苦的,但现在来看,富文本编辑器不应用用 Markdown 语法,而是 WYSIWYG 模式已经是共识了。
### 从段落到区块、从文章到应用
简单来说,即 Markdown 已经不适应当前 HTML 丰富的生态了,能轻松描述段落的标记语言,遇到富有交互的组件区块时,不得不引入例如 [MDX](https://mdxjs.com/) 等方案,但这样的方案根本只适合程序员群体,完全无法移植。
网络浏览形态也从简单的文章发展到具有整体性的应用,这些应用拥有复杂的布局、样式与交互,如果你尝试基于 Markdown 拓展语法来支持,最后可能发现还不如直接用原生 HTML。
### 对结构化内容的诉求
从编程角度理解就是 “组件复用”。Markdown 原生语法无法实现内容的复用,如果必须要复用内容,只能将其重复写在每一处,势必造成巨大同步成本。
比如 Jekyll 就提出了 [FrontMatter](https://jekyllrb.com/docs/front-matter/) 概念用来创建复用的变量:
```yml
---
food: Pizza
---
<h1>{{ page.food }}</h1>
```
### WYSIWYG 编辑器不应将 HTML 作为底层数据结构
虽然浏览器真正将 HTML 作为底层数据结构,但这并不代表所见即所得的编辑器也可以如此,这也是为什么浏览器只能提供从源码到 UI 的输出,而不能提供从 UI 编辑到源码的反向输入。
因为用户的输入与 HTML 并不是一一对应关系,其中存在大量模糊地带,比如当前光标处在粗体与细体文字中间,那下一个输入到底算加粗还是不加粗呢?从 UI 上看不到加粗标签。再有,如果 HTML 存在冗余,其实当前光标所在位置已经被加粗标签包裹了好几层,但因为光标所在区域又被另一个样式标签覆盖成非加粗模式,当再次输入时可能就跳出了覆盖范围,重新变成了加粗,这个过程符合用户预期吗?从技术上,这种复杂标签结构也几乎无法被处理,因为组合花样实在太多。
现代大多数编辑器都以 JSON 格式存储数据结构,就因为其结构化且易于检索。
结构化最重要的体现是,其生成的 HTML 结构可以是稳定的,即对于一个既加粗又标红的文字,一定包裹在一个 `<strong style="color: red">` 标签里,而不是 `<strong><div style="color: red">`,也就是这种模式根本没把 HTML 作为结构化数据去看待,自然就不会出现歧义。
Markdown 也是一样,其本身也会出现类似 HTML 标签的二义性,不适合作为底层数据结构存储。
## 精读
批判 Markdown 的文章不多见,笔者也是看了之后才恍然发现 Markdown 竟然有这么多缺点。笔者结合自己的经验谈谈 Markdown 的缺点吧。
### 不支持富交互的无奈
Markdown 仅能支持简单的 HTML 结构,而无法描述逻辑区块。Github 上大部分 Readme 都采用图片来实现这些功能,包括状态卡片、构建结果、个人信息名片等,可惜交互能力还是太弱,我觉得有朝一日 Github 应该会推出比如 Block 小区块的概念,让这些区块可以直接插入 Markdown 成为一个可交互的元素。
### MDX 解决了 Markdown 的痛点吗?
看似完美兼容 JSX 与 Markdown 的 MDX 曾经也是笔者写作的救命稻草,但该方案移植性是一大痛点,组件只能在自己部署的网站用,如果你想把文章发布到另一个平台,完全不可能。
这还仅是笔者的视角,如果从 Markdown 生态来看,MDX 面向用户仅是程序员群体,根本没有解决其使命 “方便网络写作”,而程序员最终也会抛弃 MDX 而转向开发所见即所得编辑器解决问题。
### Markdown 到 HTML 的转换存在逻辑问题
Markdown 本质上还是一种脱离 HTML 的文本表示结构,看上去解耦很优雅,实际上会遇到不少不一致的问题。
比如说连续敲击多个空格会出现什么情况呢?在 Markdown 会变成一个引用区块,那如何才能展示多个空格呢?谁也不知道,可能需要查阅具体平台提供的额外语法才可以做到。
这种大体上用起来方便,但细节无法定制,甚至用户无法控制的情况会大大伤害已经深度使用 Markdown 的用户,此时用户要么硬着头皮发明新语法解决这些漏洞,要么就完全放弃 Markdown 了。
### 结构化能力不足
看上去 Markdown 的语法挺具有结构化的,但实际上 Markdown 的结构化不具有强约束力。
拿 JSON 作对比,比如我们可以用 JSON 拓展出 [https://json-schema.org/](jsonSchema) 结构,这个结构甚至可以反推出一个完整的表单应用,其原因是 JSON 可以针对每一个 Key、层级下定义,首先有结构,其次才有内容。
而 Markdown 正好反过来,是先有内容,再有结构。比如我们可以在 Markdown 任何地方写任何 HTML 标签,或者任意段落的问题,这些内容是无法被序列化的,即便我们按照浏览器解析 HTML 的规则解析成 JSON,也无法从中方便的提取信息。
背后的根本原因是,Markdown 本身定位就是 “近乎于 UI 渲染结果” 的,而实际上浏览器渲染 UI 背后是需要一套严谨的 HTML 语法,因为 UI 与背后语法并不能一一建立映射,一个稳定的渲染逻辑只能是从源码推导到渲染,而不能从渲染反推出源码。Markdown 本身定位就近乎于渲染结果,所以结构化能力不足是天然的问题。
## 总结
记得语雀早期内部试用时,编辑态还是采用 Markdown 的,但后来很快就把 Markdown 的编辑入口下掉了,这件事还引发了不少开发者的不满,甚至还有一些 Markdown 编辑的插件被开发出来,一度很受欢迎。但渐渐的我们都习惯用所见即所得方式编辑了,Markdown 唯一留给我们的印象就是快捷键,比如 `###` 后敲入空格可以生成 `h3` 标题段落,而语雀编辑器也在富交互组件区块上越走越远,要是当年被 Markdown 锁定住了技术,也不可能有今天这么高级的编辑体验。
所以技术前瞻性真的很重要,Markdown 所有程序员都爱,但提前看到它在当前互联网发展阶段的局限性,并设计一套结构化数据代替 Markdown 结构不是所有人都能想到的,我们需要以动态的眼光看待技术,也要放下技术人的偏见,把偏爱让位于产品定位。
> 讨论地址是:[精读《对 Markdown 的思考》· Issue #397 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/397)
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**
> 关注 **前端精读微信公众号**
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)