出于我无法满足的好奇心,我甚至想在Markdown中嵌入一个低代码平台。用户只需要编写简单的文章就能完成一些系统设计任务。
首先我先假定现代Markdown编辑器的特点:
-
首先,它基于云存储和共享
-
除了文章外,相关资源也需要在线存储
-
它可以利用人工智能来撰写和微调特定段落以涵盖特定细节
-
用户应能够设计自己的数据和表单,以在文章内收集必要的信息
-
它需要跨平台支持, 它可以嵌入到任何其他Web系统中
-
它应支持协作式多用户编辑
-
它可以使用各种MDX组件,方便未来扩展
在继续下一部分内容之前,让我们来观看一段完成品的视频
我们接下来应该做什么?
首先,接下来的步骤是技术选型
我想澄清,在我完全开发出这款编辑器之后,才撰写了这篇文章。接下来的许多设计决策都是经过漫长而曲折的过程得出的,一开始并没有如此清晰的愿景。
为了确保以Markdown编写的文章最终能够在线呈现,它们的内容应该由Web进行渲染
毫无疑问,我应该选择React。虽然我更倾向于新兴的SolidJS,但我们最初的愿景是在未来集成更多MDX组件。因此,我应该选择更大的React生态系统。
Frontend choice: React
对于桌面客户端容器,也有许多选项:Electron、Tauri、PWA安装位置应用程序。 我尝试比较了这些选项,并决定首先排除PWA,因为如果我需要在将来为客户端增加复杂的本地服务以获得更强大的功能,它会对我造成限制。至于Tauri,它代表了未来,但整个工具链尚未成熟,而且我更喜欢编写Node.js服务,而不是Rust
Desktop container choice: Electron.
对于后端服务,我有两个选项:Node.js和Golang,这让我陷入了长时间的困境。由于我在前端使用TypeScript,选择Node.js会让我能够有效地利用trpc和Zod进行类型约束,并在前端和后端重用验证函数,从而获得良好的开发体验。然而,这会将我与JavaScript生态系统联系在一起。 另一方面,Golang提供了较低的内存开销,与Node.js类似的并发能力以及更低的无服务器成本。经过深思熟虑,我决定开发自己的脚手架,将前端请求层的代码生成与Golang后端接口结合起来。这提供了类似于trpc的开发体验,并为将来扩展到任何后端语言提供了潜力.
Backend choice: Golang.
由于用户数据存储在云中,数据库的选择至关重要。你有几个选择:MySQL、Postgres、MongoDB,包括它们的云产品,如阿里云或腾讯云的数据库, 我们可以选择任何云产品;在这里,我们只讨论数据库的类型。 由于这个项目的目标超出了简单的用户文本存储,我计划整合一个低代码平台。因此,我希望数据库能够兼容无模式(No schema)方法。 我无法避免使用关系型数据,比如用户配置、OpenAI令牌使用、文章基础目录以及一些需要强大事务支持的付款功能,这要求一个稳健的关系型数据库。然而,我还需要允许用户设计自己的表结构,类似于MongoDB存储用户设计的表,使用户能够自由设计字段。 我相信具体细节应该在未来的另一篇文章中详细阐述。目前,我将总结我的结论。
Database choice: Postgres + JSONB
由于需要帮助用户管理Markdown中提到的资源,我们需要一个对象存储解决方案。
Object storage choice: 阿里云 OSS
为了显著减少数据库读取开销,必须用一个键值内存数据库来补充系统,而在这种情况下,我们选择了Redis。通过计算,我相信在用户基数经历爆炸性增长之前,一个单独的专用Redis实例应该完全足够。
Cache database choice: Redis
与Redis相比,请求和CDN层的缓存确实可以更高效。它可以帮助减少数百万次的重复请求。 CDN被分布在全球各地的附近节点上。
比CDN还要更高效的缓存是用户自己的设备。由于用户可能有大量文章,不适合使用本地存储进行存储;我们需要利用indexedDB。
通过利用indexedDB -> CDN -> Redis -> Postgres作为这些缓存层,我们可以将Postgres上的开销显著降低到一个非常低的水平。
Request caching choice: IndexedDB + CDN
我希望用户能够利用人工智能来优化文章的细节,因此选择一个AI产品是至关重要的。 在这方面,毫无疑问,OpenAI的GPT-3.5是体验最简单且最佳的选择。GPT-4.0的成本太高,使得用户难以负担得起。
现在GPT-3.5已经支持微调,我们可以以非常低的开发成本实现出色的效果。
AI choice: OpenAI's GPT-3.5.
事情正在逐渐变得更加复杂,测试技术的选择确实至关重要。
我需要在测试方面做一些决策。单元测试应该涵盖哪些领域?前后端测试应该如何进行?我在这个领域有一些经验,甚至开发了一个小型的开源自动化测试平台:github.com/ymzuiku/tes...
对于后端单元测试,我正在使用Golang内置的测试库。然而,由于我接触过JS生态系统中的交互式测试方法,比如Vitest和Jest,我对这种方法产生了喜爱之情。我喜欢能够在终端中专注于特定的测试,在所有测试之间快速迭代,并且我开发了一个小型的CLI工具,它在Go内置的测试工具之上包装了一些简单的终端命令,实现了类似Jest的开发体验:github.com/ymzuiku/goj...
对于前端测试,我正在使用Vitest进行单元测试,对于端到端测试,我正在使用Cypress。
Testing choices: Go test + Vitest + Cypress
对于程序部署和持续集成/持续交付(CI/CD),有许多选择可供选择。在我的场景中,GitHub Actions已经完全足够,而且作为免费选项,它也是一种成本效益较高的选择。
CI/CD choice: GitHub Actions
下一篇文章即将到来 (如果有人点赞的话)
上述列表涵盖了项目中使用的许多技术。在接下来的文章中,我将尝试逐步描述我是如何开发这个项目的,为上面提到的技术栈提供实际的见解