读见

别再做粗糙的一次生成 SaaS 替代品|Railway 的产品打磨经验

原题Please… Enough with the Sloppy, One-Shot SaaS Replacements — Mahmoud Abdelwahab, Railway

约 11 分钟原文英文已翻译

视频由 YouTube 提供

推荐理由AI 生成的软件离日常可用还差哪些细节?这份内部工具实践适合产品开发者,用自动保存、撤销和运行环境操作检查补齐构建成功后的体验。

看前速览

4 个要点

Railway 的内部工具实践表明,要让编码 Agent 做出日常可用的软件,需要稳固的代码结构、明确的交互要求和真实环境验证。

  1. 为 Agent 提供一致的基础

    结构清晰的代码库和可复用抽象,能减少每项生成的功能各自引入新模式。

  2. 明确要求用户依赖的交互

    自动保存、即时反馈、撤销、归档和 URL 状态,都需要具体的产品要求。

  3. 复用范例和偏好

    已有页面及 Agent 技能可以传递界面约定、数据访问方式和部署要求。

  4. 实际操作运行中的应用

    构建与测试通过之后,还要沿真实用户路径完整走一遍。

完整摘要

Mahmoud Abdelwahab 介绍了 Railway 如何用一套内部应用替代多个营销 SaaS 工具,统一处理内容、邮件、社交发布、媒体素材、创作者关系和上线计划。他首先建立可复用的代码抽象,让 Agent 新增功能时沿用既有约定。随后,他指出 Agent 往往不会主动补齐的产品细节:不打断输入的自动保存、失败时能恢复的乐观更新、撤销与归档、可分享的 URL 状态,以及减少重复翻页的导航。现有页面和 Agent 技能可以传递界面、数据获取与部署规范。最后,团队仍须从头到尾操作运行中的功能,因为构建成功、测试通过也可能留下糟糕的实际体验。分享提供了具体做法,但没有量化节省或采用效果。

章节

文字稿

查看原文

简要说明Brief Description

拜托……别再搞那些草率的一次性 SaaS 替代品了——Mahmoud Abdelwahab,RailwayPlease… Enough with the Sloppy, One-Shot SaaS Replacements — Mahmoud Abdelwahab, Railway

目录Table of Contents

  • 替换 Railway 的内部营销工具
    Replacing Railway's internal marketing tools
  • 一致功能的结构与抽象
    Structure and abstractions for consistent features
  • 需要请求产品打磨代理提供帮助。
    Product polish agents need to be asked for
  • 自动保存与协作
    Autosave and collaboration
  • 乐观更新、撤销和归档
    Optimistic updates, undo and archiving
  • URL 状态与导航
    URL state and navigation
  • 参考页面和智能体技能
    Reference pages and agent skills
  • 从头到尾验证该功能是否正常运行
    Verify the running feature from start to finish

替换 Railway 的内部营销工具Replacing Railway's internal marketing tools

人们说 SaaS 已经不行了,这话说了有一阵子了。现在这甚至都算不上什么惊人观点。既然你可以自己动手,为什么还要花钱请人来开发和维护你用的工具呢?直接让你的智能体去做就好了。对我来说,还有一个很少被提及的关键问题:那些一次性生成出来、能运行的软件,和我真正愿意使用的软件之间,存在着一道鸿沟,而且这道鸿沟很大。真正的软件能让人感到愉悦,打磨得精致,用起来很舒服。实际上,我确实着手用自建工具取代我们在 Railway 内部用于营销的一批 SaaS 服务商。我搭建了一个我们自己使用的一体化工具。它让我们能够管理 Railway 网站上的内容、更新日志和博客;还能用来发送邮件、同时在所有社交平台上发布内容,以及管理网站媒体资源。People have been saying that SAS is dead for a while now. It's not even a hot take at this point. Why pay someone to build and maintain the tools you use when you could just do it yourself? Just ask your agent to do it. And for me, there's one missing piece that rarely gets mentioned. And it's the fact that there's a gap, a big gap between working software that got oneshotted and software I would actually use. Software that sparks joy, that is polished, that feels good. and actually went on a journey to replace a bunch of SAS providers we're using internally at Railway for marketing purposes. And I just built an all-in-one tool that we use. The tool allows us to manage content for the Railway website, change log, blog. We can use it to send emails, post on all of our social platforms at the same time, manage the website's media.

甚至还有一个迷你 CRM,这样我们在和外部创作者合作时,就能跟踪相关进展。还有任务跟踪、发布规划,因为你知道,我们需要协调多项事务以及它们的发布时间。这里有日历,也有评论和实时协作编辑,而这一切都是用智能体构建的。我觉得 GPT6 发布时,真正的突破来了,而这一切都运行在 Railway 上。所有东西都会自动部署。接下来,我来介绍一下我用来确保新增功能真正打磨到位、与应用其他部分保持一致的一些原则,同时也分享一些你可以借鉴并应用到自建工具中的原则。所以,我决定换个环境,不在我那间乏味的办公室里做演讲,而是到户外来讲。There's even a mini CRM so that when we're working with like external creators, we can keep track of that. There is task tracking, launch planning because you know you want to coordinate multiple things and when they'll go out. There's a calendar and at the same time there's like comments, realtime editing and it's all built using agents. I would say I felt the breakthrough when GPT6 came out and all of this is running on railway. Everything just auto deploys. And let me essentially now walk you through the principles I use to actually make sure that when I want to add a feature, it's, you know, actually polished and matches the rest of the app and at the same time the principles that you can pull from and apply when building tools of your own. So instead of doing my talk from my boring office, I decided to switch things up and do it outside.

这里简直美极了。我现在在苏格兰的爱丁堡,感觉美得不真实。我就坐在外面的长椅上,这就是我眼前的景色。这长椅绝对能打十分。这次对我来说,聊这类话题的感觉和以往有点不一样,因为我基本上会带你们走一遍我打造我们自己的内部工具的历程,以及我在这个过程中形成的看法。不过我也明白,整个领域的变化非常非常快。所以我说的任何事情,可能短短几个月后就会彻底改变。谁知道呢?总之,我也说不好。就把这当作我的免责声明吧。录制时间是2026年秋天,也就是10月。嗯。所以,话说回来,我们来聊第一个观点:文本不重要。It is absolutely beautiful. Right now I'm in Edinburgh, Scotland, and it's just unreal. Like I'm on a bench outside and this is my view. Definitely a 10 out of 10 bench. Now this type of talk for me feels a little bit different than what I'm used to because I essentially will walk you through the journey of me building our own internal tools and the opinions I've developed. But I also understand that the landscape changes very very quickly. So like anything I say might change completely in like the span of months. Who knows? So I don't know. Consider this my disclaimer. Like but the time of recording is fall 2026. It's October. And yeah. So anyway, with that out of the way, uh let's talk about the first point which is texts don't matter.

一致功能的结构与抽象Structure and abstractions for consistent features

现在很多人都说,用什么编程语言、什么框架都无所谓。你只要让智能体帮你构建任何东西,它就能做到。虽然我在一定程度上同意,但我发现,当你在构建一个自己真正会用的工具时,如果给智能体提供一个抽象设计扎实的代码库,那么在开发新功能时,最终得到的结果会更加一致,也会更贴近你之前构建的内容。原因其实很简单:智能体不需要每次添加新功能时都重新发明同样的“轮子”,也不需要引入新的模式。它基本上只要沿用现有模式就行。至于该选什么,我觉得其实不太重要,只要你的代码库结构合理就好。Now, a lot of people say that it doesn't matter what programming language you use, what framework you use. You can just ask your agent to build you anything and build it is able to do it. And while I agree to some extent, what I found is when you're building a tool that you will actually use, when you give the agent a proper codebase with solid abstractions, what ends up happening is whenever you're working, let's say, on a new feature, you end up with a much more consistent result that is similar to what you've already built before. And the reason is like it's very simple. the agent doesn't need to reinvent the same like wheel every time it tries to add a new feature or it doesn't need to introduce new patterns. It will just essentially follow existing patterns. And when it comes to like what you choose, I feel like it kind of doesn't really matter as long as you have a code base that is properly structured.

不过,我现在在 Web 开发中首选的是 TanStack 系列库。如果你要构建任何与内容相关的东西,我会说一定要用 Payload。体验很棒,抽象也做得很好。我之前一度深陷比较各种 CMS 的“兔子洞”,因为我不觉得自己应该从头开始构建,尽管我确实做得到。不过话说回来,谁知道呢?也许未来会变。总之,这就是我最先遇到的主要选择。But like my go-to choice today is one tan stack libraries for anything when building on the web. And if you're building anything content related, I would say definitely go with payload. Solid experience, great abstraction. I went down like a big rabbit hole of like comparing CMSS at some point because I don't believe that I should uh build it from scratch even though I can. But again, who knows? Maybe the future will change. But yeah, and that's kind of like the main first item that I kind of ran into.

需要请求产品打磨代理提供帮助Product polish agents need to be asked for

当你像用户一样,每天使用许多自己很喜欢的 SaaS 产品时,有很多事情你都不会注意到。但当你真的尝试复现某种体验时,你很快就会发现,各种流程背后倾注了多少心思和讲究。比如说,像“我想发封邮件”或者“我想发布点东西”这么简单的需求,你完全可以用一个老派的服务端渲染应用来实现,配上提交表单就行了。但如果你想构建一个人们每天都会用、经常会打开来用的东西,你就会觉得:“它不应该是这种感觉。”我发现有不少设计模式,除非你明确要求,否则智能体通常不会主动采用。这就是我的清单。When you use like a lot of SAS products out there that you actually love that you use every day, when you're a user, there's like a lot of things you don't notice, but when you actually try to like replicate an experience, you quickly find out how much care and thought goes into different flows. So like something as simple as oh I want to be able to send an email or to publish something. You can easily do it by having like a good old you know just like server side rendered app with like forms that you submit. But if you try to build something that is going to be used every day that you will reach for a lot you're like oh it shouldn't feel that way. And there are kind of like a bunch of patterns that I found that agents don't typically do unless you explicitly ask them to. And this is my list.

所以我们将……So we'll

自动保存与协作Autosave and collaboration

我们逐一来看。第一个是自动保存。我发现,如果你在构建某种文档编辑器,自动保存算是一个基础标配功能。因此,你不必手动点击保存来保存内容,只要让它在后台自动保存进度,并确保这是一个非阻塞操作。这样,比如你在打字时,就可以继续输入,内容也会自动保存。你还可以更进一步,防止浏览器标签页在存在未保存更改时关闭。这就像是两层保障,确保你正在处理的内容不会丢失。你还可以再进一步,加入实时协作功能,这样就能支持多人并发编辑。go through them one by one. And the first one is like autosave. I found that if like let's say I'm building some form of document editor, autosave is kind of like a table stakes feature. So rather than manually clicking save to save things, you just ask it to automatically save progress in the background and to make sure that it's like a non-blocking action so that you can let's say if as you're typing you're able to type and then it just automatically saves. And one other kind of like step further that you could do is to also prevent the browser tab from closing if there are unsafe changes. So it's kind of like this these two layers that kind of guarantee that whatever it is that you're working on is just not going to be lost. Now you can also go a step further and to add like real-time collaboration so that you can have like concurrent edits.

而且再说一次,我的智能体添加这个功能时一点都没费劲。就像是,怎么说呢,先问问这个功能,看看它会如何运作,然后等这些都完成之后,And again, my agent didn't struggle at all with adding the feature. It was like, I don't know, asking about it, reviewing how it would work, and then once that's done,

主持人:仅仅又过了 7 亿个 token,我就有了实时体验。所以,总的来说,这是我发现智能体从产品角度来看做得不太好的第一件事。Host: just 700 million tokens later, I had real time. So, I would say in general, this is the first thing that I find agents just don't do well from a product

乐观更新、撤销与归档Optimistic updates, undo and archiving

从用户体验的角度来看,我还发现另一种智能体完全忘了实现的模式:乐观更新。与其在用户执行任何操作时都让他们看着一堆加载动画,不如先乐观地向他们展示操作成功后的状态,同时在后台同步他们所做的更改。如果同步或操作因任何原因失败,只需回滚更改,然后告诉他们操作没有成功。当然,你不应该对所有事情都盲目采用乐观更新。有些情况下,你需要显示加载动画,并等待确认一切是否正常完成。但总的来说,乐观更新能显著提升整体体验的速度感,让交互更加顺畅,也让一切感觉即时得多。experience perspective. Another pattern I found that agents completely forget to implement is optimistic updates. So rather than showing your users a bunch of loading spinner whenever they're taking any action, you essentially show them the success state you know optimistically and in the background you're going to sync whatever change they made. Now if the sync or the operation fails for whatever reason you just roll it back and then tell them like oh the operation work. Now of course you shouldn't blindly have optimistic updates for everything. There are some scenarios where you want to show the user a loading spinner and you're going to wait to check that everything worked properly. But in general, having optimistic updates makes the overall experience feel significantly faster, much snappier, and it will just feel much more instant.

所以我相当确定,你可以直接问你的智能体:“嘿,我想在合适的地方实现乐观更新。我们来制定一个计划吧。”它就会告诉你哪些地方适合这么做。再说一次,让智能体实现这项功能并不难。你只需要开口,并且清楚自己要问什么。在我看来,乐观更新的延伸之一,就是让用户能够撤销某些操作。举个例子,如果你让智能体实现删除记录的功能,它通常会给你一个删除按钮。你点击它,可能会看到一个确认对话框,点下确认后,它才会真正删除记录。但更好的体验是允许用户撤销这个操作。也就是说,他们点击删除后,你立即从界面上移除要删除的项目,同时告诉他们:“嘿,你还有几秒钟可以改变主意。”So pretty sure you can just ask your agent like, "Hey, I would like to implement optimistic updates where it makes sense. Let's come up with a plan." And it will tell you all the areas where it makes sense to do. Again, it's like it's not difficult for the agent to build it. You just need to ask and know exactly what to ask for. Now, an extension of optimistic updates, in my opinion, is giving users the ability to undo certain actions. Now, for example, if you ask your agent to implement the ability to delete records, what it will typically do is it will give you a delete button. You click it, might show a confirmation dialogue, you hit confirm, and then it will actually do the deletion. But a much nicer experience is actually allowing the user to undo that action. So they hit delete, you immediately remove the item they want to delete from the UI, but you tell them like, hey, you have like a couple of seconds where you could change your mind.

如果他们什么都不做,那就意味着你确实想删除某个东西。然后你才真正执行删除操作。否则,如果他们点击撤销,你就恢复所做的更改。所以,这有点像是在后台也执行了这个操作。它本质上是一种延迟操作,这也引出了下一个要点:归档。你应该告诉你的智能体,你希望能够归档记录,也能取消归档,因为有时你想让某些内容完全不显示在界面上,或者不出现在搜索结果中,而归档就是实现这一目的的方式。你不应该逼着用户说:“如果你不想看到这个,就只能删除它。”更好的体验是让用户能够移出记录。所以我认为,这种模式绝对应该存在。And if they don't do anything, that means you actually want to delete a thing. Then you actually implement the operation. Otherwise, if they hit undo, you just bring back the change. So it's kind of like you do the operation in the background as well. It's just kind of a delayed action which kind of ties into the next point which is archiving. You should tell your agent you want the ability to archive records and be able to unarchive them because sometimes you want to hide something from the UI completely or let's say from search results and archiving will be the way to do it and you shouldn't force your user to be like well if you don't want to see this you have to delete it. and a much better experience is just the ability to walk out records. So I think it is a pattern that should definitely exist.

URL 状态与导航URL state and navigation

对我来说,另一个很重要的点是 URL 状态。当然,只要合适,你就应该让你的代理把状态保存在 URL 中,这非常实用。比如,你有一份记录列表,想要筛选或排序,而你又设置了一堆条件,把这些内容保存在 URL 中,就能轻松地分享给别人。这样,假设另一位团队成员打开链接,就能准确看到你希望他们看到的内容。还有一个代理默认不会实现的小细节,就是无限滚动。我不想一次又一次地点“加载更多”,也不想点“下一页”按钮;我滚动时就应该直接看到数据,不需要点击下一页。最后,我只要看到“已经到底了”就行。这只是个很小的细节,但如果你每天都在用,我觉得它会带来很大不同。另一个我发现能显著提升输出效果的模式是……Another big one for me is URL state. you should ask your agent to persist in the URL whenever it makes sense of course and it's so useful because whenever you have let's say a list of records and you want the ability to filter or sort them and you just have a bunch of like conditions maintaining these things in the URL makes it trivial for you to give them to someone else and then let's say another team member is just going to be able to see exactly what you want them to see now another small detail that agents don't implement out of the box is infinite scroll I don't want to be clicking on load more over and over and over or like a next page button as I scroll I should just get the data I shouldn't need to click next page and then in the end I'll just see that oh I've reached the end it's a very minor thing but also when you use something every day I think it makes a huge difference now another pattern I found that made the output significantly

参考页面和代理技能Reference pages and agent skills

更好的做法是明确告诉智能体,涉及 UI、数据获取方式、工作原理以及整体结构时,要参考现有页面。这样我就能先把好的效果定义好,然后在开发更多功能时重复使用。说实话,有时候即使你告诉智能体“嘿,把 X 页面当作参考”,它有时还是不会照做。我也不知道是不是模型有时会变笨,但这种情况确实会发生。不过总的来说,我觉得告诉智能体参考现有页面,成功率会更高,因为这样也能带来更一致的体验。比如你在使用应用时会觉得:“哦,这和应用的另一部分很一致”,尤其是两边采用了相同的概念时。better is telling the agent explicitly to use existing pages as references when it comes to the UI the data fetching and how it works works and how the thing is overall structured and that made it possible for me to essentially define what good looks like once and then just reuse it for more features. Now to be completely honest sometimes even when you tell the agent like hey use page X as a reference sometimes it just doesn't follow it. I don't know if models like get dumber sometimes but sometimes it does happen. But overall, I would say that my success rate is higher whenever I tell the agent to like, well, use an existing page as a reference because you also just end up with a more consistent experience. So like as you're using your app, you're like, oh, this just matches the other part of the app if they both share like the same concept.

比如说,如果应用中的两个部分本质上都是记录列表,支持创建、更新、删除和查看列表,那么这两部分就应该基本保持一致。这就引出了我的下一个观点:每当你对某件事有自己的看法时,都应该把它封装成 agent skills。这样一来,你的智能体在构建东西时,就会严格遵循这些技能。在构建我们所有的内部工具时,我发现自己会用到三项 agent skills。其中两项与设计工程有关。一项能让 UI、排版、布局以及整体的错误提示都变得更好;另一项则是一套设计工程技能,能让动画等效果做得更好。</numerusformSo like if two parts of the app are essentially lists of records that you can create update and delete and like list well both of these parts should be pretty much identical. This list kind of brings me to my next point which is whenever you have opinions about something they should be packaged as agent skills and then this way your agent whenever it's building something it will actually follow those skills pretty closely. And as I was building all of our internal tooling, I found myself reaching for three Asian skills. Uh two of them are related to design engineering. So one made it easier to have better UI, better typography, better layouts as well as like better error messages in general. And the second one was a set of design engineering skills that made it easier to just have better animations and other things like that.

最后但同样重要的是 Railway 的亚洲技能。当然,我在 Railway 内部为我们搭建的一切都运行在 Railway 上,比如存储桶、数据库、应用本身、实时服务器,所有东西都是如此。要让智能体有效地使用 Railway 并能够部署所有内容,你只需给它亚洲技能,它就能做到。是的,所以,一旦你拥有了所有的亚洲技能以及其他一切,在我……And then last but not least is the railway Asian skills, of course. So like everything that I built for us internally at railway runs on railway of course like everything. So like buckets, databases, the app itself, the real-time server, everything. And for the agent to effectively work with railway and be able to deploy everything, you just give it the Asian skills and it was just able to do it. And yeah, so like once you have all of your Asian skills and everything, in my

从头到尾验证正在运行的功能Verify the running feature from start to finish

我认为,最后一步,也是我觉得最重要的一步,就是验证。通常,每当你让智能体构建某样东西,它都会说:“好了,我已经实现了这个功能,构建通过,测试也通过了,一切正常。”对吧?但我发现,实际试用时,有时候体验会糟糕得一塌糊涂。所以,一旦你建立起验证闭环,效果就会有天壤之别,因为你可以亲眼看到智能体这样做:“好,我做出了这个东西。我试了一下,失败了。我要修复它。”然后它就会一直继续下去。最后,它会说:“好了,我已经彻底测试过了。”当计算机使用能力变得非常非常强时,我感觉这是一次突破。现在,每次我想添加新功能,最后都会直接说:你应该验证这个功能能否端到端地正常运行,并通过实际运行基础设施来进行端到端测试。智能体完全有能力做到这一点。opinion, the final step and I think this the most important step is verification. So the agents typically whenever you ask it to build something, it's going to be like, okay, I implemented the feature, build passed, test pass, all good, right? But what I found is when you actually try out what happens, you sometimes end up with just like a very broken experience. So once you have like a verification loop in place, it's like a night and day difference because the agent you can literally see it be like, "Okay, I built this thing. I tried it. It failed. I'm going to fix it." And it just keeps going. And then in the end, it's like, "Okay, I fully tested it." And I felt this breakthrough with computer use once it got really, really good. And now everything every time I want to add a new feature I literally just in the end say well you should verify that the feature works end to end and use it by actually running infrastructure and to test things end to end and the agents are very capable of doing this.

你只需要告诉他们,而一旦你具备了所有这些要素,我想你最终就能打造出扎实的内部工具,既能快速构建,又能正常运行,而且表现始终如一。就是这样。这就是我在构建任何内部工具时都会遵循的原则清单。希望你觉得这些原则有用;更重要的是,希望它们能激励你打造属于自己的内部工具,让它们用起来顺手、打磨精良,并带来愉悦感。我也希望你能成为你们公司的 SAS 层。感谢收看,我们下次再见。You just have to tell them and once you have all those pieces I would say you will end up with solid internal tools that you can build quickly that work properly and work in a consistent way. And that's it. This was my list of principles that I use whenever I'm building any internal tools. Hope you found them useful, but more importantly, that you're inspired to build your own internal tools that feel good, that are polished, and spark joy. And I hope that you too can become your company's SAS layer. And with that, thank you so much for watching and I'll see you in the next

值得记下

我发现 Agent 经常完全忘记实现乐观更新。
但我发现,真正试用之后,有时得到的体验仍然很糟糕。