1
00:00:02,201 --> 00:00:04,841
People have been saying that SaaS is dead for a while now.

2
00:00:04,841 --> 00:00:06,601
It's not even a hot take at this point.

3
00:00:06,981 --> 00:00:11,741
Why pay someone to build and maintain the tools you use when you could just do it yourself?

4
00:00:12,021 --> 00:00:13,241
Just ask your agent to do it.

5
00:00:13,521 --> 00:00:17,621
And for me, there's one missing piece that rarely gets mentioned.

6
00:00:17,901 --> 00:00:23,201
And it's the fact that there's a gap, a big gap between working software that got one-shotted

7
00:00:23,201 --> 00:00:25,501
and software I would actually use.

8
00:00:25,621 --> 00:00:28,321
Software that sparks joy, that is polished, that feels good.

9
00:00:28,481 --> 00:00:33,181
And I actually went on a journey to replace a bunch of SaaS providers we were using internally

10
00:00:33,181 --> 00:00:34,761
at Railway for marketing purposes.

11
00:00:35,081 --> 00:00:37,541
And I just built an all-in-one tool that we use.

12
00:00:37,661 --> 00:00:39,201
The tool allows us to manage content

13
00:00:39,201 --> 00:00:41,561
for the Railway website, change log, blog.

14
00:00:41,781 --> 00:00:43,181
We can use it to send emails,

15
00:00:43,721 --> 00:00:46,641
post on all of our social platforms at the same time,

16
00:00:47,001 --> 00:00:47,921
manage the website's media.

17
00:00:48,141 --> 00:00:50,541
There's even a mini CRM so that when we're working

18
00:00:50,541 --> 00:00:52,981
with external creators, we can keep track of that.

19
00:00:53,301 --> 00:00:55,561
There is task tracking, launch planning,

20
00:00:55,801 --> 00:00:57,741
because you wanna coordinate multiple things

21
00:00:57,741 --> 00:00:59,801
and when they'll go out, there's a calendar.

22
00:00:59,801 --> 00:01:06,501
and at the same time there's like comments real-time editing and it's all built using

23
00:01:06,501 --> 00:01:13,581
agents i would say i felt the breakthrough when gpt6 came out and all of this is running on railway

24
00:01:13,581 --> 00:01:20,001
everything just auto deploys and let me essentially now walk you through the principles i use

25
00:01:20,001 --> 00:01:25,981
to actually make sure that when i want to add a feature it's you know actually polished and

26
00:01:25,981 --> 00:01:33,001
matches the rest of the app and at the same time the principles that you can pull from and apply

27
00:01:33,001 --> 00:01:37,881
when building tools of your own so instead of doing my talk from my boring office i decided to

28
00:01:37,881 --> 00:01:43,181
switch things up and do it outside it is absolutely beautiful right now i'm in edinburgh scotland

29
00:01:43,181 --> 00:01:51,941
and it's just unreal like i'm on a bench outside and this is my view definitely a 10 out of 10

30
00:01:51,941 --> 00:01:57,521
bench. Now, this type of talk for me feels a little bit different than what I'm used to, because

31
00:01:58,261 --> 00:02:04,241
I essentially will walk you through the journey of me building our own internal tools and the

32
00:02:04,241 --> 00:02:09,821
opinions I've developed. But I also understand that the landscape changes very, very quickly.

33
00:02:10,101 --> 00:02:18,341
So like anything I say might change completely in like the span of months. Who knows? So I don't

34
00:02:18,341 --> 00:02:25,821
know consider this my disclaimer like but the time of recording is fall 2026 it's october and

35
00:02:25,821 --> 00:02:33,601
yeah so anyway with that out of the way uh let's talk about the first point which is text acts don't

36
00:02:33,601 --> 00:02:38,881
matter now a lot of people say that it doesn't matter what programming language you use what

37
00:02:38,881 --> 00:02:42,901
framework you use you can just ask your agent to go do anything and those are able to do it

38
00:02:42,901 --> 00:03:05,121
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 code base 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.

39
00:03:06,121 --> 00:03:08,101
And the reason is, like, it's very simple.

40
00:03:08,381 --> 00:03:15,061
The agent doesn't need to reinvent the same, like, wheel every time it tries to add a new feature,

41
00:03:15,201 --> 00:03:16,841
or it doesn't need to introduce new patterns.

42
00:03:16,841 --> 00:03:20,081
It will just essentially follow existing patterns.

43
00:03:20,581 --> 00:03:25,161
And when it comes to, like, what you choose, I feel like it kind of doesn't really matter

44
00:03:25,161 --> 00:03:29,561
as long as you have a code base that is properly structured.

45
00:03:29,561 --> 00:03:36,041
But my go-to choice today is, one, TanStack libraries for anything when building on the web.

46
00:03:36,461 --> 00:03:40,461
And if you're building anything content-related, I would say definitely go with payload.

47
00:03:40,741 --> 00:03:42,741
Solid experience, great abstraction.

48
00:03:43,021 --> 00:03:51,701
I went down a big rabbit hole of comparing CMSs at some point because I don't believe that I should build it from scratch, even though I can.

49
00:03:52,221 --> 00:03:53,461
But again, who knows?

50
00:03:53,701 --> 00:03:55,001
Maybe the future will change.

51
00:03:55,001 --> 00:04:01,641
but yeah and that's kind of like the main first item that i kind of ran into

52
00:04:05,321 --> 00:04:09,541
when you use like a lot of sas products out there that you actually love they use every day

53
00:04:10,641 --> 00:04:16,221
when you're a user there's like a lot of things you don't notice but when you actually try to like

54
00:04:16,221 --> 00:04:23,121
replicate an experience you quickly find out how much care and thought goes into different flows

55
00:04:23,121 --> 00:04:29,701
So something as simple as, oh, I want to be able to send an email or to publish something.

56
00:04:30,821 --> 00:04:39,741
You can easily do it by having a good old server-side rendered app with forms that you submit.

57
00:04:39,941 --> 00:04:45,021
But if you try to build something that is going to be used every day that you will reach for

58
00:04:45,021 --> 00:04:48,201
a lot, you're like, oh, it shouldn't feel that way.

59
00:04:48,601 --> 00:04:56,481
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.

60
00:04:56,941 --> 00:05:00,461
And this is my list. So we'll go through them one by one.

61
00:05:00,741 --> 00:05:09,141
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 states feature.

62
00:05:10,581 --> 00:05:23,901
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.

63
00:05:24,161 --> 00:05:29,941
So that you can, let's say, as you're typing, you're able to type and then it just automatically saves.

64
00:05:29,941 --> 00:05:41,041
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.

65
00:05:41,301 --> 00:05:48,721
So it's kind of like these two layers that kind of guarantee that whatever it is that you're working on is just not going to be lost.

66
00:05:49,141 --> 00:05:57,021
Now, you can also go a step further and to add like real time collaboration so that you can have like concurrent edits.

67
00:05:57,021 --> 00:06:01,001
And again, my agent didn't struggle at all with adding the feature.

68
00:06:01,201 --> 00:06:06,241
It was like, I don't know, asking about it, reviewing how it would work.

69
00:06:06,401 --> 00:06:11,661
And then once that's done, just 700 million tokens later, I had real time.

70
00:06:11,901 --> 00:06:19,621
So I would say in general, this is the first thing that I find agents just don't do well from a product experience perspective.

71
00:06:19,981 --> 00:06:24,101
Another pattern I found that agents completely forget to implement is optimistic updates.

72
00:06:24,101 --> 00:06:28,521
So rather than showing your users a bunch of loading spinner whenever they're taking any action,

73
00:06:28,821 --> 00:06:32,501
you essentially show them the success state optimistically.

74
00:06:33,021 --> 00:06:36,641
And in the background, you're going to sync whatever change they made.

75
00:06:36,961 --> 00:06:40,821
Now, if the sync or the operation fails for whatever reason,

76
00:06:41,041 --> 00:06:44,601
you just roll it back and then tell them, like, oh, the operation didn't work.

77
00:06:44,881 --> 00:06:48,881
Now, of course, you shouldn't blindly have optimistic updates for everything.

78
00:06:49,081 --> 00:06:52,941
There are some scenarios where you want to show the user a loading spinner

79
00:06:52,941 --> 00:06:56,061
and they're going to wait to check that everything worked properly.

80
00:06:56,361 --> 00:06:59,261
But in general, having optimistic updates

81
00:06:59,261 --> 00:07:02,861
makes the overall experience feel significantly faster,

82
00:07:03,281 --> 00:07:06,741
much snappier, and it will just feel much more instant.

83
00:07:07,201 --> 00:07:10,301
So pretty sure you can just ask your agent like,

84
00:07:10,421 --> 00:07:13,121
hey, I would like to implement optimistic updates where it makes sense.

85
00:07:13,341 --> 00:07:15,701
Let's come up with a plan and it will tell you all the areas

86
00:07:15,701 --> 00:07:16,661
where it makes sense to do.

87
00:07:16,901 --> 00:07:19,861
Again, it's like it's not difficult for the agent to build it.

88
00:07:19,861 --> 00:07:25,481
you just need to ask and know exactly what to ask for. Now an extension of optimistic updates in my

89
00:07:25,481 --> 00:07:32,781
opinion is giving users the ability to undo certain actions. Now for example if you ask your agent to

90
00:07:32,781 --> 00:07:38,041
implement the ability to delete records what it will typically do is it will give you a delete

91
00:07:38,041 --> 00:07:42,701
button you click it might show a confirmation dialog you hit confirm and then it will actually

92
00:07:42,701 --> 00:07:49,621
do the deletion. But a much nicer experience is actually allowing the user to undo that action

93
00:07:49,621 --> 00:07:55,641
so they could delete you immediately remove the item they want to delete from the ui but you tell

94
00:07:55,641 --> 00:08:01,721
them like hey you have like a couple of seconds where you could change your mind and if they don't

95
00:08:01,721 --> 00:08:07,281
do anything that means you actually want to delete a thing then you actually implement the operation

96
00:08:07,281 --> 00:08:13,581
otherwise if they hit undo you just bring back the change so it's kind of like you do the operation

97
00:08:13,581 --> 00:08:19,021
in the background as well it's just kind of a delayed action which kind of ties into the next

98
00:08:19,021 --> 00:08:25,181
point, which is archiving, you should tell your agent you want the ability to archive records

99
00:08:25,181 --> 00:08:30,961
and be able to unarchive them. Because sometimes you want to hide something from the UI completely,

100
00:08:31,201 --> 00:08:36,061
or let's say from search results, and archiving will be the way to do it. And you shouldn't

101
00:08:36,061 --> 00:08:39,281
force your user to be like, well, if you don't want to see this, you have to delete it.

102
00:08:39,581 --> 00:08:45,361
Any much better experience is just the ability to archive records. So I think it is a pattern

103
00:08:45,361 --> 00:08:47,161
that should definitely exist.

104
00:08:47,441 --> 00:08:48,941
Another big one for me is URL state.

105
00:08:49,161 --> 00:08:51,301
You should ask your agent to persist in the URL

106
00:08:51,301 --> 00:08:52,501
whenever it makes sense, of course.

107
00:08:52,821 --> 00:08:54,961
And it's so useful because whenever you have,

108
00:08:55,101 --> 00:08:56,001
let's say, a list of records

109
00:08:56,001 --> 00:09:00,621
and you want the ability to filter or sort them

110
00:09:00,621 --> 00:09:03,181
and you just have a bunch of conditions,

111
00:09:04,181 --> 00:09:06,561
maintaining these things in the URL

112
00:09:06,561 --> 00:09:09,021
makes it trivial for you to give them to someone else.

113
00:09:09,141 --> 00:09:10,601
And then, let's say, another team member

114
00:09:10,601 --> 00:09:11,861
is just going to be able to see

115
00:09:12,361 --> 00:09:13,901
exactly what you want them to see.

116
00:09:13,901 --> 00:09:17,241
Now another small detail that agents don't implement out of the box is infinite scroll.

117
00:09:17,481 --> 00:09:22,861
I don't want to be clicking on lobe more over and over and over or like a next page button.

118
00:09:23,401 --> 00:09:26,441
As I scroll, I should just get the data.

119
00:09:26,801 --> 00:09:28,241
I shouldn't need to click next page.

120
00:09:28,361 --> 00:09:30,981
And then in the end, I'll just see that, oh, I've reached the end.

121
00:09:31,161 --> 00:09:32,301
It's a very minor thing.

122
00:09:32,341 --> 00:09:36,181
But also when you use something every day, I think it makes a huge difference.

123
00:09:36,741 --> 00:09:41,321
Now another pattern I found that made the output significantly better is telling the

124
00:09:41,321 --> 00:09:47,681
agent explicitly to use existing pages as references when it comes to the ui the data

125
00:09:47,681 --> 00:09:53,841
fetching and how it works and how the thing is overall structured and that made it possible for

126
00:09:53,841 --> 00:10:00,661
me to essentially define what good looks like once and then just reuse it for more features now

127
00:10:00,661 --> 00:10:07,921
to be completely honest sometimes even when you tell the agent like hey use page x as a reference

128
00:10:07,921 --> 00:10:13,461
sometimes it just doesn't follow it i don't know if models like get dumber sometimes but sometimes

129
00:10:13,461 --> 00:10:19,061
it does happen but overall i would say that my success rate is higher whenever i tell the agent

130
00:10:19,061 --> 00:10:24,301
to like well use an existing page as a reference because you also just end up with a more consistent

131
00:10:24,301 --> 00:10:29,581
experience so like as you're using your app you're like oh this just matches the other part of the

132
00:10:29,581 --> 00:10:35,821
app if they both share like the same concept so like if two parts of the app are essentially

133
00:10:35,821 --> 00:10:42,901
lists of records that you can create, update, and delete and list. Well, both of these parts

134
00:10:42,901 --> 00:10:47,941
should be pretty much identical. This list kind of brings me to my next point, which is whenever

135
00:10:47,941 --> 00:10:52,041
you have opinions about something, they should be packaged as agent skills. And then this way,

136
00:10:52,221 --> 00:10:57,401
your agent, whenever it's building something, it will actually follow those skills pretty closely.

137
00:10:57,721 --> 00:11:03,081
And as I was building all of our internal tooling, I found myself reaching for three agent skills.

138
00:11:03,081 --> 00:11:09,181
two of them are related to design engineering so one made it easier to have better ui better

139
00:11:09,181 --> 00:11:14,761
typography better layouts as well as like better error messages in general and the second one was

140
00:11:14,761 --> 00:11:19,601
a set of design engineering skills that made it easier to just have better animations and other

141
00:11:19,601 --> 00:11:24,061
things like that and then last but not least is the railway agent skills of course so like

142
00:11:24,061 --> 00:11:30,841
everything that i built for us internally at railway runs on railway of course like everything

143
00:11:30,841 --> 00:11:35,601
So like buckets, databases, the app itself, the real-time server, everything.

144
00:11:35,881 --> 00:11:39,981
And for the agent to effectively work with Railway and be able to deploy everything,

145
00:11:40,361 --> 00:11:43,581
you just give it the Railway agent skills and it was just able to do it.

146
00:11:44,321 --> 00:11:48,521
And yeah, so like once you have all of your agent skills and everything,

147
00:11:48,781 --> 00:11:54,541
in my opinion, the final step, and I think the most important step, is verification.

148
00:11:55,581 --> 00:11:58,321
So the agents typically, whenever you ask it to build something,

149
00:11:58,541 --> 00:12:00,501
it's going to be like, okay, I implemented the feature.

150
00:12:01,101 --> 00:12:03,901
build pass, test pass, all good, right?

151
00:12:04,141 --> 00:12:07,681
But what I found is when you actually try out what happens,

152
00:12:07,881 --> 00:12:11,361
you sometimes end up with just like a very broken experience.

153
00:12:12,401 --> 00:12:15,501
So once you have like a verification loop in place,

154
00:12:15,501 --> 00:12:17,181
it's like a nine day difference

155
00:12:17,181 --> 00:12:19,301
because the agent, you can literally see it,

156
00:12:19,521 --> 00:12:20,921
be like, okay, I built this thing.

157
00:12:21,341 --> 00:12:22,161
I tried it.

158
00:12:22,301 --> 00:12:22,941
It failed.

159
00:12:23,141 --> 00:12:23,921
I'm going to fix it.

160
00:12:24,421 --> 00:12:25,741
And it just keeps going.

161
00:12:25,941 --> 00:12:27,901
And then in the end, it's like, okay, I fully tested it.

162
00:12:27,901 --> 00:12:32,861
And I felt this breakthrough with computer use once it got really, really good.

163
00:12:33,001 --> 00:12:47,481
And now 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.

164
00:12:47,661 --> 00:12:49,641
And the agents are very capable of doing this.

165
00:12:49,821 --> 00:12:50,761
You just have to tell them.

166
00:12:51,481 --> 00:12:53,561
and once you have all those pieces,

167
00:12:53,881 --> 00:12:58,181
I would say you will end up with solid internal tools

168
00:12:58,181 --> 00:12:59,361
that you can build quickly,

169
00:12:59,761 --> 00:13:01,941
that work properly and work in a consistent way.

170
00:13:02,141 --> 00:13:02,681
And that's it.

171
00:13:02,821 --> 00:13:04,701
This was my list of principles that I use

172
00:13:04,701 --> 00:13:06,061
whenever I'm building any internal tools.

173
00:13:06,281 --> 00:13:07,101
Hope you found them useful.

174
00:13:07,281 --> 00:13:08,121
But more importantly,

175
00:13:08,381 --> 00:13:11,901
that you're inspired to build your own internal tools

176
00:13:11,901 --> 00:13:15,221
that feel good, that are polished and spark joy.

177
00:13:15,441 --> 00:13:18,821
And I hope that you too can become your company's SaaS layer.

178
00:13:19,221 --> 00:13:21,021
And with that, thank you so much for watching, and I'll see you in the next one.
