以产品进行工程思维设计

假期期间,我找到了一些空闲时间,决定着手一个项目来解决自己的问题。在这篇博文中,我将带您了解我要解决的问题、我构建解决方案的方法,以及托管基础架构和技术堆栈如何由产品本身塑造。结果是一个简化的工作流程,使我能够快速行动,同时遵守我的一些关键工程原则:可读性、性能和有效使用 TypeScript。

作为工程师,很容易陷入过度复杂化的陷阱——无论是过度设计解决方案,还是依赖标准化的技术堆栈,而这些技术堆栈并不总是最适合项目。这篇文章重点介绍了如何采取以产品为导向和了解基础设施的方法来帮助解决问题。

虽然这篇文章不是开发教程,但您可以在 GitHub 上查看代码:https://github.com/ScottHarrisonDev/cc-aggregator-game/tree/main。

要解决的问题

作为一群汽车爱好者,我和我的朋友们喜欢讨论我们的梦想之车。我们假设拥有的车辆清单不断变化。不久前,我们开始玩一个游戏,一个人分享一张收藏汽车拍卖清单的截图,其余人选择一辆我们假设拥有一年并承担所有费用的汽车。接下来的对话总是令人欢迎的,特别是因为我们见面的次数并不像我们希望的那样频繁。

这个游戏一开始很简单,但很快就变得复杂起来。起初,我会截取浏览器窗口中显示的任何列表的屏幕截图。然而,我很快就遇到了问题:

A screenshot of the basic Collecting Cars listing page

偶尔,会出现车牌或摩托车的列表,这些都不属于我们的游戏范围。然后我开始应用“仅限汽车”过滤器。

A screenshot of the Collecting Cars listing page with

我不得不缩小屏幕以便将更多汽车放入屏幕截图中。

A screenshot of the Collecting Cars listing page zoomed out to show more results

广告经常会悄悄出现,需要我在分享截图之前在 Chrome Devtools 中手动将其删除。

A screenshot of the Collecting Cars listing page with an advert highlighted in the Chrome Devtools ready to be removed

以前拍摄和分享只需不到 10 秒,现在每天只需花几分钟。那时我意识到我可以自动化这个过程,或者至少简化它。

要求

从高层次来看,我们的目标是展示一个包含 12 辆来自 Collecting Cars 的汽车的页面,供我和我的朋友在群聊中讨论。数据将来自 Collecting Cars 的实时拍卖页面,过滤为“仅限汽车”,可能仅限于英国。

游戏将基于以下示例收集汽车 URL:https://collectingcars.com/buy?refinementList[listingStage][0]=live&refinementList[regionCode][0]=UK&refinementList[lotType][0]=car

概念验证

💡 注意:从内部 API 获取数据或抓取 HTML 通常比较麻烦且不可靠,应在生产应用程序中避免使用。它还会给源网站带来额外成本。

该项目最大的未知数是如何检索数据。一种方法是复制内部 API 请求以获取原始数据。另一种方法是像用户一样向页面发出请求后直接抓取页面的 HTML。

经过一番调查,我发现 Collecting Cars 使用 Algolia 来获取其客户端的产品列表。我能够复制他们的请求,简化它,并使用 Postman 检查是否可以检索有用的响应。果然,它成功了!我现在可以访问 JSON 格式的拍卖数据。

A screenshot of the Chrome Devtools showing the request to AlgoliaA screenshot of Postman displaying a successful response

构建

我最初使用 Astro 和 Tailwind CSS 构建了“收集汽车”页面的副本,以简化的布局显示 12 辆汽车。这反映了我们之前玩游戏的方式,我会发送网站部分内容的屏幕截图。

A screenshot of my initial game website build

“简单模式”

我们在原版游戏中经常遇到的一个问题是,从 12 辆汽车中只选择一辆太难了,很多人都会选择多个选项。为了解决这个问题,我创建了一个“简单模式”,将选项限制为 3 辆汽车,这样就更容易选择一辆了(理论上!)。

A screenshot of the easy mode version of the game with only 3 options

然而,玩了几天后,我意识到“简单模式”实际上更有趣、更快捷,而且只有 3 个选项。因此,我进一步简化了游戏,将“简单模式”设为唯一可用模式。

A screenshot of the refined standard game mode with only 3 options

移动造型

最初,我以为这款游戏主要在桌面端进行,因为我们过去经常分享桌面端网站的截图。但很快我就发现,用户现在会直接访问网站,并在群聊中分享他们的选择,因此移动端的使用成为主要情况。

考虑到这一点,我使用 Tailwind CSS 的移动优先方法对设计进行了细微调整,使其更适合移动设备。这些更改实施起来很快,并且有助于维护干净、可读的代码库。

A screenshot of the site at mobile size

基础设施

作为基于 Astro 的站点,该项目可以静态生成或服务器端渲染(SSR)。

一种选择是使用 Cloudflare Worker Pages 和 Astro Cloudflare 适配器进行 SSR。但是,由于游戏每天只玩一次,并且没有即时逻辑,因此 SSR 不会带来任何好处。此外,不同用户在不同时间查看网站时可能会看到不同的汽车选择,这并不理想。使用 Cloudflare,我可以引入一个缓存层来存储页面 24 小时,但这会增加不必要的复杂性。

另一种选择是依靠静态生成。虽然我对其他托管服务提供商有更多的经验,但我知道 GitHub Pages 支持 Astro 项目的静态生成。这里的主要限制是汽车选择只有在我重建和部署网站时才会更新。

我曾短暂考虑过设置一个 Raspberry Pi 在我的本地网络上运行并通过 Cron 作业触发重建。然而,经过进一步研究,我发现 GitHub Actions 支持计划的工作流程,允许我每天在设定的时间触发重建。这个解决方案简单、免费,保留了静态生成的好处,同时与源网站 API 兼容(每天只会调用一次,而不是像使用 SSR 时每次有人访问网站时调用)。

A screenshot of the GitHub Action Workflow

我将工作流添加到代码库中,并添加了页脚注释以显示上次更新时间(部分是为了调试,但也是为了让缺席一天后回来的用户能够确保他们看到的是最新选择)。这已经顺利运行了几天,并且表现符合预期。

A screenshot of the GitHub Actions dashboard

结论

在现代网络开发中,我们很容易默认使用 Next.js 或 React 等工具,并结合使用 Vercel 等平台进行托管,尤其是对于我们想要依赖已知技术的个人项目。然而,这可能会导致解决方案不理想,需要付出额外的努力才能将方枘圆凿。

这并不是说你应该总是使用不熟悉的技术,而是应该根据产品的需求选择适合工作的工具,即使它不是你熟悉的东西。个人项目是试验这种思维方式的绝佳机会,这将在商业环境中为你带来好处。

该项目的源代码可以在我的 Github https://github.com/ScottHarrisonDev/cc-aggregator-game 上找到,你可以在 https://scottharrisondev.github.io/cc-aggregator-game/ 上查看该游戏