自项目启动以来,您在多年间使用 Haskell 进行生产的经验有何变化?

Description of your first forum.
Post Reply
rabiakhatun785
Posts: 531
Joined: Wed Jan 22, 2025 10:16 am

自项目启动以来,您在多年间使用 Haskell 进行生产的经验有何变化?

Post by rabiakhatun785 »

我觉得我们扩展 Web 应用程序的方式并没有发生太大变化;我们主要添加新的 HTTP 端点和表。例如,我最近添加了一个评论交易的功能,这与我们刚添加端点时的早期编码没有太大区别。

然而,随着我们开发了以银行业务层为中心的更深层次的系统,我们必须构建一个具有特定正确性保证的账本。这需要更多重写,这在 Web 应用程序中很正常,因为核心逻辑在不断发展。

不过,总体而言,变化并不大。我们现在 泰国电话号码 改进了数据库事务的类型安全性。以前,任意操作(例如在事务期间发出 HTTP 请求)可能会导致稳定性问题,例如死锁或耗尽数据库事务池。

借助 Haskell 的类型安全,如果您处于数据库事务中,则无法发出任意 HTTP 请求。相反,您只能执行安全操作,例如日志记录。这是生产代码库中的常见挑战,但 Haskell 有助于在编译时防止此类问题,而不像其他需要时刻警惕的语言。

你发现哪些工具或库对于 Haskell 来说是不可或缺的?在这么长的一段时间内,在生产环境中进行开发。
我们使用的 Web 框架名为 Yesod。它由 Michael Snoyman 编写。Yesod 有点像 Ruby on Rails。我们几乎不使用 Yesod 的所有功能,因为我们只是从 Web 服务器返回 JSON。因此,我们使用的主要库是 Persistent(数据库库),然后是 Esqueleto(Persistent 的扩展,可让您执行更高级的查询,例如跨表连接和通用表表达式等)。

所以,这些是迄今为止最常见的库。我们还使用其他库,但在大多数情况下,持久性 SQL 编辑器是您在编写新功能时要处理的库。

如何平衡纯函数式编程原则与实际业务需求?
我不认为函数式编程原则与实际业务需求相冲突。从业务角度来看,函数式编程的许多好处与他们的需求相符。纯函数是没有副作用的函数;它接受某些键和值的映射并返回一个新映射。在我之前的公司,我遇到了一个本应是纯函数的函数,但实际上修改了传递给它的映射。这导致了一个难以跟踪的错误,我不得不在临时服务器上通过生产数据库逐步调试。业务部门不希望我们花时间调试本应由简单函数引起问题的问题。

能够提取部分代码并简化代码真是太好了。例如,将接受 map 到 map 的函数移到其自己的块中,可以让与数据库交互和解析 JSON 的主要代码变得更小、更清晰。这使得棘手的部分更容易阅读,这对于大约 95% 的应用程序来说是理想的。

虽然可能会有权衡——例如在处理深度嵌套的纯函数时,这种情况很少见——但您可能需要重构代码以适应指标。我们的代码库中有一个用于指标的 monad,但这是一个快速重构。

您可以创建一个免费的架构,构建一个纯粹的潜在操作树和一个该树的解释器,从而允许在顶部实现业务逻辑。但是,我们很少使用 Haskell 达到这种复杂性,因此对我们来说,没有什么重大的权衡。

如何平衡初创公司的快速迭代需求和 Haskell 的编译时保证?与投入生产相比,这些保证是否会减慢开发速度?
这是个好问题。它有很多优点和缺点。当编译器为你做更多工作时,它最终可能会变得更慢。这就像比动态类型语言检查更多的保证,但它什么都没有给你,或者像 Go 这样的语言提供的保证比 Haskell 少得多。不仅要快速将代码投入生产,还需要快速将正确的代码投入生产。如果你部署了有问题的代码并不得不恢复它,这对客户来说是可怕的,也会扰乱开发团队。此外,如果你将错误推送到生产中,通常很难追踪它。调查这种情况比在本地环境中调查要困难得多。

这就是为什么我认为拥有这些编译时保证真的很棒。当你扩展到更大的公司时,它变得更加重要。如果代码库长达一百万行,你需要保证在系统的一个区域进行更改不会破坏另一个区域。Haskell 为你提供了更多能力来实现这一点。

我已经很久没有做过超级干净的构建了。我想说大概需要 12 分钟。但通常情况下,我们使用一种 Haskell 的解释版本,它不会加载您不需要的东西。您可以为您正在查看的代码设置一个重新编译的 REPL。这就是 GHCI 具有该功能的原因,或者我们使用 GHCID(它之前的开源版本)。此时生产编译非常慢;我认为构建和运行测试大约需要 30 分钟。这就是我们投资这个 Buck2 系统的原因:我们希望为需要真正优化构建的 CI 生产构建提供更好的缓存。
Post Reply