时间跟踪革命:Quarkus 如何改变了我们的后端开发

GRAN Software Solutions 是一家德国公司,致力于设计和构建现代后端解决方案。我们与大型汽车客户和其他客户合作,重组和创建新的解决方案。我们还开发并提供 SaaS 工具,以帮助我们和他人进行日常工作。
我们为自己和他人构建的一个这样的工具是一个名为 Sheetty 的时间跟踪应用程序。
时间跟踪挑战

我们需要创建一个时间跟踪应用程序,因为市场上现有的解决方案无法满足我们的特定需求。它们要么不是为开发人员设计的,要么缺乏我们需要的简洁性,要么加载了不必要的功能。我们希望构建一个完美满足我们需求的工具,利用我们多年来在客户项目中所获得的丰富经验。我们还希望创建一个更现代和用户友好的设计,使用起来会很有趣,并融入 Quarkus 等较新的技术。
我们现有的时间跟踪解决方案面临的主要问题是缺乏一种在客户之间轻松切换的方式。我们还发现它们不支持我们习惯的快速操作或快捷方式,并且没有可视化方式来查看我们当天所做的时间记录。此外,我们希望根据与客户签订的合同(按每日费率和合同上限)来跟踪时间。这就是为什么我们决定创建一个自定义解决方案来解决所有这些特定需求。
发现 Quarkus
当我们选择用于后端的的技术栈时,我们的主要目标是使用我们已经熟悉的技术,例如 Kotlin 编程语言、Spring Boot 框架和 Postgres 数据库。我们还希望选择一个可以为我们提供数据库连接、Web 客户端、缓存和其他类似功能的库的生态系统。此外,我们希望使用高性能解决方案来降低我们的托管成本并避免高内存需求。
在分析了市场上各种解决方案后,我们决定使用 Quarkus 框架,因为它满足了我们的所有要求。
我们使用 Quarkus 的后端开发经验:主要功能
我们已经将我们的应用程序架构设计为将前端和后端部分分开。为了以现代和安全的方式保护我们的后端 API,我们选择使用 JSON Web Tokens,Quarkus 对它们有很好的支持。我们还对我们的 API 使用基于角色的安全性,Quarkus 使我们能够轻松实现这一点。我们的应用程序中有不同的角色,例如普通用户和管理员,这些信息编码在我们的 JSON Web Tokens 中。Quarkus 确保这些令牌在到达我们的后端系统时不会被篡改或操纵。
@RolesAllowed
用于授权我们的 API 端点@Path("/clients")
@RolesAllowed("User")
@Produces(MediaType.APPLICATION_JSON)
@ApplicationScoped
class ClientResource(
private val getClientsHandler: GetClientsHandler,
private val newClientHandler: NewClientHandler,
我们非常依赖丰富的 JSON 支持来灵活地建模我们的数据,并将大部分功能委托给 Postgres 本身来操作数据。这样,我们可以将已构建的 JSON 对象传递回 API 客户端,这大大减少了在应用程序代码中做出设计决策所需的时间。Quarkus 为 JSON 对象 API 提供了出色的支持。我们认为,出于性能和代码维护的原因,Postgres 是执行数据操作和聚合的正确位置,而不是应用程序代码。
JsonObject
来传递我们的数据@GET
@Produces(MediaType.APPLICATION_JSON)
suspend fun getProfile() = db.preparedQuery(
"""select profile from "user" where email = $1""".trimIndent()
).execute().awaitSuspending().first().getJsonObject("profile")
虽然 Quarkus 主要面向 Java 编程语言,但 Kotlin 支持也非常好。我们使用了协程和挂起函数,与其他一些可用的异步编程模型相比,这可以实现更高的性能和更简单的代码。Kotlin 的结构化并发使我们能够编写看似顺序的代码,但实际上是非常高性能的异步代码。Quarkus 提供了构建在现有异步 API(例如 Mutiny)之上的出色的 Kotlin 扩展方法。
我们在应用程序启动时执行数据库迁移,这对我们来说非常重要。幸运的是,Quarkus 对 Flyway 有很好的支持,因此我们所有的数据库迁移都放在一个地方,并在我们的后端启动过程中执行。这使我们的数据库模式和数据保持透明和可重现。

对于我们的部署,我们使用 Kubernetes。在使用 Quarkus 之前,我们使用 Helm 打包描述了我们的应用程序需求,但使用 Quarkus,我们选择了另一种方法,因为 Quarkus 提供了出色的 Kubernetes 扩展。我们没有编写任何代码,而是使用 application.yaml
文件描述了我们的 Kubernetes 资源,从而将我们完整的应用程序配置保存在一个地方。此扩展在幕后生成 Kubernetes 资源文件,然后我们将其应用于我们的 Kubernetes 集群。这对我们来说效果很好。

对于打包我们的后端 API,我们使用了 Jib 扩展。要将我们的应用程序打包到容器中,我们所要做的就是使用 application.yaml
文件并设置所有必需的参数,例如图像名称标签存储库等等。我们不必自己维护 Docker 文件,这非常方便。
我们的时间跟踪应用程序需要在各种场合向我们的用户和管理员发送电子邮件。为了简化事情,我们决定不采用任何第三方 API 驱动的电子邮件发送方法。相反,我们自己发送电子邮件,为此,我们使用 Qute 电子邮件模板,这使得编写电子邮件并将其发送给我们的用户非常简单。此扩展提供对编码协程的支持,从而可以进行非阻塞发送和更高的吞吐量。

开发之旅
到目前为止,Quarkus 的开发过程一直很棒。与 Spring Boot 等其他框架相比,Quarkus 具有更快的启动时间和更小的内存占用。它还提供配置文件,这使我们可以在环境之间具有略有不同的配置或行为。我们可以轻松地用本地模拟替换一些难以运行的第三方服务,而无需更改应用程序代码。Quarkus 在配置方面也很棒,以及我们可以轻松地使用外部环境变量覆盖存储在 application.yaml
文件中的值。虽然热重载模式在 Kotlin 中效果不佳,但我相信所有与它相关的错误将在即将发布的版本中得到解决。在开发期间,我们必须大部分时间重新启动正在运行的服务,才能使代码更改生效。
我们的后端 API 功能大约花了一个半月的时间完成。考虑到只有两名开发人员在后端工作,我认为这是一个很好的结果。在我们产品生命周期的这个阶段,由于不断重新审视需求和我们的需求,我们决定不编写自动化测试。相反,我们暂时选择手动测试。一旦我们的时间跟踪应用程序拥有更多活跃用户,我们计划开始使用 Quarkus 测试支持(包括 Testcontainers 等)编写自动化测试。开发一个完整的 API,包括具有 JSON Web Tokens 的 API 安全性和授权,在应用程序启动时自动应用数据库迁移,具有围绕 JSON 的灵活且可维护的代码库,并能够将我们的 API 打包并部署到我们的 Kubernetes 集群,对于仅仅一个半月的工作来说,这是一项相当大的成就。
结论
我们很高兴分享,使用 Quarkus、Kotlin 和 Postgres 作为我们后端 API 的基础,对我们来说是一次有趣且富有成效的体验。Quarkus 快速实验和利用现成组件的能力使我们确信我们做出了正确的技术选择。尽管热重载和 Kotlin 存在一些缺陷,但我们正在等待修复,并且毫不怀疑 Quarkus 是最适合我们的解决方案。
我们正在努力工作,为我们的时间跟踪应用程序带来新功能。为了实现这一目标,我们将继续使用 Quarkus 提供的强大功能,这些功能可以大大减少快速推出我们的功能所需的时间。我们邀请您在 sheetty.com 尝试我们的时间跟踪器。