WEBVTT

1
00:00:00.000 --> 00:00:01.180
Awesome, guys.

2
00:00:01.180 --> 00:00:03.360
Welcome back to our Tuesday training.

3
00:00:03.360 --> 00:00:07.560
We're hanging out with the team here again every Tuesday.

4
00:00:07.560 --> 00:00:09.480
We've been doing these internal team trainings,

5
00:00:09.480 --> 00:00:12.160
and now we're just going to be publishing them on YouTube X.

6
00:00:12.160 --> 00:00:14.400
So go follow us over there.

7
00:00:14.400 --> 00:00:16.280
And you can kind of stay tuned to how

8
00:00:16.280 --> 00:00:18.720
we're teaching different things on everything

9
00:00:18.720 --> 00:00:21.520
from shape up to breadboarding to how to use AI,

10
00:00:21.520 --> 00:00:23.960
how to vibe code professionally.

11
00:00:23.960 --> 00:00:26.720
These are all the topics that we're covering here.

12
00:00:26.720 --> 00:00:28.920
And so today, we're kind of picking up on a part two

13
00:00:28.920 --> 00:00:31.880
from Jonato, who's one of our team members in Brazil.

14
00:00:31.880 --> 00:00:34.920
And he, last week, did an awesome training

15
00:00:34.920 --> 00:00:36.240
on kind of an intro to Flutter.

16
00:00:36.240 --> 00:00:38.720
So if you haven't seen that, go check that out.

17
00:00:38.720 --> 00:00:39.920
And today, we're going to kind of wrap up

18
00:00:39.920 --> 00:00:42.320
that introduction to Flutter, but also

19
00:00:42.320 --> 00:00:44.960
talk about how we're using Flutter specifically

20
00:00:44.960 --> 00:00:47.920
in Tribe Social, which is our main product we've

21
00:00:47.920 --> 00:00:49.320
been building the last few years.

22
00:00:49.320 --> 00:00:53.640
So we originally did have that project in Flutter Flow,

23
00:00:53.640 --> 00:00:56.600
and then we finally exited that and put it into Flutter.

24
00:00:56.600 --> 00:00:58.640
And now we've been kind of rebuilding and refactoring

25
00:00:58.680 --> 00:00:59.400
the whole project.

26
00:00:59.400 --> 00:01:02.040
So if you're working on any part of Flutter on our team,

27
00:01:02.040 --> 00:01:03.440
or if you're just curious how we're

28
00:01:03.440 --> 00:01:05.960
using Flutter for Tribe Social, this will be a good video.

29
00:01:05.960 --> 00:01:08.120
So I'm going to hand it over to Jonato.

30
00:01:10.920 --> 00:01:12.480
So hey, everyone.

31
00:01:12.480 --> 00:01:13.960
Nice to be here again.

32
00:01:13.960 --> 00:01:18.040
And for this session, I wanted to start

33
00:01:18.040 --> 00:01:22.200
with just reviewing the key takeaways from last session,

34
00:01:22.200 --> 00:01:26.280
just so we are on the same page and to keep things fresh.

35
00:01:26.360 --> 00:01:32.000
And then we'll dive directly into how Tribe architecture

36
00:01:32.000 --> 00:01:33.840
is currently looking like.

37
00:01:33.840 --> 00:01:39.560
And we'll review one specific case

38
00:01:39.560 --> 00:01:44.000
where we had to migrate from Flutter flow code,

39
00:01:44.000 --> 00:01:50.400
let's say, to a more well-architected and cleaner

40
00:01:50.400 --> 00:01:54.320
way of building things, and how we did this migration,

41
00:01:54.320 --> 00:01:58.320
and what are the key things we keep in mind while doing

42
00:01:58.320 --> 00:01:59.600
this kind of migration.

43
00:01:59.600 --> 00:02:02.760
So let's start.

44
00:02:02.760 --> 00:02:05.600
So reviewing the four main takeaways

45
00:02:05.600 --> 00:02:07.480
from our last session, basically,

46
00:02:07.480 --> 00:02:11.680
so Flutter has this cross-platform power.

47
00:02:11.680 --> 00:02:14.880
We build once and deploy everywhere, mobile, web,

48
00:02:14.880 --> 00:02:16.840
desktop.

49
00:02:16.840 --> 00:02:24.400
And it has a, I wouldn't say like a native performance,

50
00:02:24.400 --> 00:02:27.680
but a very close to native, especially

51
00:02:27.680 --> 00:02:29.360
on the mobile side of things.

52
00:02:29.360 --> 00:02:35.960
The Flutter handling is doing a good job on this side.

53
00:02:35.960 --> 00:02:41.760
Of course, with some, let's say, with some differences,

54
00:02:41.760 --> 00:02:45.800
depending on which kind of feature

55
00:02:45.800 --> 00:02:48.720
or which kind of structure you need to show,

56
00:02:48.720 --> 00:02:53.080
like if you are going to be very animation-oriented

57
00:02:53.080 --> 00:02:57.720
and you are going to need heavy animation, let's say,

58
00:02:57.720 --> 00:03:02.480
then sometimes you may see some type of stuttering,

59
00:03:02.480 --> 00:03:05.760
but that's not the overall experience.

60
00:03:05.760 --> 00:03:10.520
So it's a very stable cross-platform tool.

61
00:03:10.520 --> 00:03:12.800
Also, we have the widget-first thinking.

62
00:03:12.800 --> 00:03:15.240
So like we saw in the previous session,

63
00:03:15.240 --> 00:03:17.360
everything on Flutter is a widget.

64
00:03:17.360 --> 00:03:22.320
And we compose complex UIs using simple reusable blocks

65
00:03:22.320 --> 00:03:24.760
using this declarative syntax.

66
00:03:24.760 --> 00:03:31.800
And this part of using reusable building blocks

67
00:03:31.800 --> 00:03:33.440
is very important.

68
00:03:33.440 --> 00:03:36.240
And I will show how we think about it

69
00:03:36.240 --> 00:03:41.160
when we are migrating from the Flutter flow-generated code,

70
00:03:41.160 --> 00:03:46.720
which, in general, tends to generate a lot bigger

71
00:03:46.720 --> 00:03:50.480
than needed pieces of code, and how we broke this down

72
00:03:50.480 --> 00:03:53.600
into smaller and more reusable components

73
00:03:53.600 --> 00:03:58.600
that we can use across different places in the application.

74
00:03:58.600 --> 00:04:01.560
We also reviewed some of the Dart's modern features,

75
00:04:01.560 --> 00:04:04.760
so strong typing, new safety, how

76
00:04:04.760 --> 00:04:08.920
it's handled async and await, and asynchronous communication

77
00:04:08.920 --> 00:04:11.360
in general, and a few patterns that

78
00:04:11.360 --> 00:04:15.040
makes our code safer and more maintainable.

79
00:04:15.040 --> 00:04:20.760
And we also saw a bit of the state management in Flutter,

80
00:04:20.760 --> 00:04:24.760
starting with the most basic one, which is the set state,

81
00:04:24.760 --> 00:04:28.200
and going up to providers and pubs

82
00:04:28.200 --> 00:04:33.120
that are specifically created for state management.

83
00:04:33.160 --> 00:04:39.120
So that were the main points from our last presentation,

84
00:04:39.120 --> 00:04:41.480
just so we had them fresh on memory

85
00:04:41.480 --> 00:04:45.720
before diving into the next thing, which

86
00:04:45.720 --> 00:04:51.880
will be our type social app architecture overview.

87
00:04:51.880 --> 00:04:55.760
So here, we'll take a quick look into how we are structuring

88
00:04:55.760 --> 00:04:58.280
things on the tribe side and how we are

89
00:04:58.280 --> 00:04:59.960
thinking about this structure.

90
00:05:00.000 --> 00:05:07.040
One important thing to note here is that this is still a work in progress.

91
00:05:07.040 --> 00:05:13.520
We've come a long way with our app and it had a lot of different phases.

92
00:05:13.520 --> 00:05:18.480
As any big production app that we have,

93
00:05:18.480 --> 00:05:22.600
it has its own stages and its own development.

94
00:05:22.600 --> 00:05:27.760
The things we start with is very different from what we have now.

95
00:05:27.760 --> 00:05:34.480
And you see that a lot of this structure, a lot of our architecture,

96
00:05:34.480 --> 00:05:38.080
also reflects the history that we have.

97
00:05:38.080 --> 00:05:41.920
So you see a lot of Flutter Flow legacy things,

98
00:05:41.920 --> 00:05:45.520
some decisions that were made in the past are still present,

99
00:05:45.520 --> 00:05:50.720
and we are always reviewing and updating things as we go.

100
00:05:50.720 --> 00:05:56.880
And the architecture is basically a snapshot of the current moment

101
00:05:56.960 --> 00:05:59.440
and how it's currently looking.

102
00:05:59.440 --> 00:06:06.720
So starting with the tech stack itself and how we are handling deployment,

103
00:06:06.720 --> 00:06:11.360
we use, of course, Flutter and Dart for mobile and web clients,

104
00:06:11.360 --> 00:06:17.920
targeting iOS, Android, and web from one single repository.

105
00:06:17.920 --> 00:06:23.600
We use Firebase services like Firestore, Auth, Storage, and Cloud Functions

106
00:06:23.600 --> 00:06:28.800
to handle a part of the logic of application

107
00:06:28.800 --> 00:06:33.360
and also managing the authentication.

108
00:06:33.360 --> 00:06:37.920
It's also important to note that we also have our own API

109
00:06:37.920 --> 00:06:44.560
that's built and separated from the Firebase structure.

110
00:06:44.560 --> 00:06:50.080
And we are currently looking to the future of migrating completely

111
00:06:50.080 --> 00:06:53.760
out of the Firebase and removing this dependency

112
00:06:53.760 --> 00:06:57.280
and only relying on our API.

113
00:06:57.280 --> 00:07:00.160
We currently have this dependency on Firebase

114
00:07:00.160 --> 00:07:04.880
because during the Flutter Flow phase of the project,

115
00:07:04.880 --> 00:07:09.760
it was a lot easier to have it integrated directly with Firestore,

116
00:07:09.760 --> 00:07:15.120
and this way you could leverage a lot of the Flutter Flow structure

117
00:07:15.120 --> 00:07:19.120
in terms of making it easier to access content from Firestore

118
00:07:19.120 --> 00:07:22.960
and to use it on the app using the Flutter Flow structure.

119
00:07:22.960 --> 00:07:26.480
But now that we are out of Flutter Flow,

120
00:07:26.480 --> 00:07:33.280
we have the ability to kind of gradually migrate off

121
00:07:33.280 --> 00:07:36.960
at least from the backend side of things,

122
00:07:36.960 --> 00:07:38.720
from out of Firebase,

123
00:07:38.720 --> 00:07:46.400
and to be able to rely on our own API for everything backend-related.

124
00:07:46.400 --> 00:07:49.120
But this is a long way.

125
00:07:49.120 --> 00:07:51.840
This is something that takes a lot of work.

126
00:07:51.840 --> 00:07:54.720
And the difficult part about refactoring

127
00:07:54.720 --> 00:07:58.640
is that customers usually don't see it.

128
00:07:58.640 --> 00:08:06.800
So it's a balancing game of delivering new features

129
00:08:06.800 --> 00:08:09.680
that customers will be able to use and see

130
00:08:09.680 --> 00:08:15.280
and also being able to refactor these parts that we are touching.

131
00:08:15.280 --> 00:08:22.160
And here on Tribe, we avoid trying to tackle refactor

132
00:08:22.160 --> 00:08:24.720
as a project in and of itself.

133
00:08:24.720 --> 00:08:28.800
So we usually associate the refactor

134
00:08:28.800 --> 00:08:35.360
with doing some feature-related thing and improving on this feature.

135
00:08:35.360 --> 00:08:39.440
And if this feature is going to touch some places in the app

136
00:08:39.440 --> 00:08:43.120
that need some refactor for some reason,

137
00:08:43.120 --> 00:08:47.760
that need to, for instance, remove some dependency,

138
00:08:47.760 --> 00:08:51.200
then we tackle them, we group them,

139
00:08:51.200 --> 00:08:54.240
and we use this as one big project.

140
00:08:54.240 --> 00:08:58.080
This way, we don't have this huge refactoring sessions

141
00:08:58.080 --> 00:09:00.000
that could take months.

142
00:09:00.000 --> 00:09:04.240
We break them in smaller pieces that are more manageable

143
00:09:04.240 --> 00:09:08.560
and allow us for what I think is actually the most important part

144
00:09:08.560 --> 00:09:13.840
to be able to do constant releases to our customers.

145
00:09:13.840 --> 00:09:23.040
And they will be gradually experiencing a better app overall.

146
00:09:24.560 --> 00:09:28.320
So we have also Flutter fully generated code

147
00:09:28.320 --> 00:09:31.280
that lives in the pages part

148
00:09:31.280 --> 00:09:33.920
and also on the component part of the app.

149
00:09:34.560 --> 00:09:38.240
But like I said, we are gradually migrating it

150
00:09:38.240 --> 00:09:43.040
from clean architecture inside the features tab,

151
00:09:43.680 --> 00:09:46.320
inside the features folder inside the project.

152
00:09:47.840 --> 00:09:51.440
And one interesting piece and one interesting fact

153
00:09:51.440 --> 00:09:57.120
and one interesting part of the Tribe's tech stack

154
00:09:57.120 --> 00:09:59.920
is that we have a flavor-driven strategy.

155
00:10:00.000 --> 00:10:03.520
structure that builds nine different apps.

156
00:10:03.520 --> 00:10:05.720
I think it's nine from my current count,

157
00:10:05.720 --> 00:10:09.640
but we build nine different apps launching

158
00:10:09.640 --> 00:10:13.400
different Firebase projects, bundles IDs, apps on the App

159
00:10:13.400 --> 00:10:17.960
Store and Android Store, and assets configured per flavor.

160
00:10:17.960 --> 00:10:20.200
So this is a very robust structure

161
00:10:20.200 --> 00:10:24.080
that we have implemented using CodeMagick,

162
00:10:24.080 --> 00:10:26.580
where from a single repository, we

163
00:10:26.580 --> 00:10:29.280
are able to deploy to nine different apps,

164
00:10:29.360 --> 00:10:32.720
and we can easily add new customers to this structure

165
00:10:32.720 --> 00:10:36.640
just by setting up the configurations file

166
00:10:36.640 --> 00:10:40.080
that you have for CodeMagick, then setting up the assets.

167
00:10:40.080 --> 00:10:44.440
Even yesterday, I think Bruce, in one afternoon,

168
00:10:44.440 --> 00:10:48.680
was able to easily, like, three to four hours.

169
00:10:48.680 --> 00:10:50.160
Yeah, that's...

170
00:10:50.160 --> 00:10:54.000
Yeah, easily is up, maybe even underrated, but yes.

171
00:10:54.000 --> 00:10:57.240
Within a few hours, we could set up someone new.

172
00:10:57.240 --> 00:11:01.280
Yeah, but see, we are kind of spoiled now,

173
00:11:01.280 --> 00:11:03.320
because now things are a lot faster.

174
00:11:03.320 --> 00:11:07.040
But in the past, like, three to four hours

175
00:11:07.040 --> 00:11:09.480
was, like, nothing in terms of development.

176
00:11:09.480 --> 00:11:14.800
Now we can do a lot in three to four hours, but yeah.

177
00:11:14.800 --> 00:11:18.560
It's nice to have this structure in place,

178
00:11:18.560 --> 00:11:22.880
and even though it's not so fast,

179
00:11:22.880 --> 00:11:30.680
but it's still very robust and allows for creating new tool,

180
00:11:30.680 --> 00:11:32.600
inviting new customers to the app,

181
00:11:32.600 --> 00:11:36.160
and creating their own white label versions of Tripe

182
00:11:36.160 --> 00:11:39.800
with too much of a hassle.

183
00:11:39.800 --> 00:11:42.560
And like I said, we did it.

184
00:11:42.560 --> 00:11:45.680
Actually, Bruce did it this yesterday afternoon

185
00:11:45.680 --> 00:11:48.880
with a new client, which was very cool to see.

186
00:11:48.880 --> 00:11:53.280
So this is a very important part of the app,

187
00:11:53.280 --> 00:11:59.920
and you see that we try to abstract this from the code

188
00:11:59.920 --> 00:12:03.680
as much as possible.

189
00:12:03.680 --> 00:12:07.520
So if you are walking through the code,

190
00:12:07.520 --> 00:12:11.360
you almost never see anything that

191
00:12:11.360 --> 00:12:15.080
will point to the fact that this is serving

192
00:12:15.080 --> 00:12:16.600
nine different apps.

193
00:12:16.600 --> 00:12:19.720
So we have specific places in the app

194
00:12:19.720 --> 00:12:22.560
that we have created abstractions layers that

195
00:12:22.560 --> 00:12:28.600
allow us to touch as little as possible of the application

196
00:12:28.600 --> 00:12:33.320
if we need to have a new customer running.

197
00:12:33.320 --> 00:12:35.560
So like I said here and here on the right,

198
00:12:35.560 --> 00:12:38.520
we have a little bit more of this new client architecture.

199
00:12:38.520 --> 00:12:41.160
So we have a Flavor Config.

200
00:12:41.160 --> 00:12:44.880
We have our CICD running with the flavor structure

201
00:12:44.880 --> 00:12:46.560
from Flutter itself.

202
00:12:46.560 --> 00:12:51.080
Flutter has this flavor system that allows

203
00:12:51.080 --> 00:12:53.440
to generate different apps.

204
00:12:53.440 --> 00:12:58.000
And this also configures the Firebase for each customer.

205
00:12:58.000 --> 00:13:01.200
So each customer has its own Firebase,

206
00:13:01.200 --> 00:13:04.560
and this keeps the shared code clean

207
00:13:04.560 --> 00:13:11.000
while injecting client-specific dependence when we need it.

208
00:13:11.000 --> 00:13:16.920
So here below, we have a, we will

209
00:13:16.920 --> 00:13:21.680
see this a little bit more in Courser directly.

210
00:13:21.680 --> 00:13:26.440
But here is, let's say, the main structure

211
00:13:26.440 --> 00:13:28.800
inside the lib folder, which is basically

212
00:13:28.800 --> 00:13:31.320
the main folder of the Flutter application.

213
00:13:31.320 --> 00:13:33.320
So we have the main, which is the entry

214
00:13:33.320 --> 00:13:34.960
point for the application.

215
00:13:34.960 --> 00:13:38.560
We have inside the config, we have the application

216
00:13:38.560 --> 00:13:42.360
configuration, including flavors.

217
00:13:42.360 --> 00:13:48.840
We have features, which are a work-in-progress, let's say,

218
00:13:48.840 --> 00:13:52.880
migration folder, where we are refactoring things and moving

219
00:13:52.880 --> 00:13:55.000
into that.

220
00:13:55.000 --> 00:13:57.720
We have the pages with all the UI screens,

221
00:13:57.720 --> 00:13:59.680
mostly generated by Flutter Flow.

222
00:13:59.680 --> 00:14:04.440
And we will see the difference between what Flutter Flow

223
00:14:04.440 --> 00:14:08.240
generated code and how it's the code that we actually want

224
00:14:08.240 --> 00:14:14.480
or a code that's more like what we want.

225
00:14:14.480 --> 00:14:16.600
The components, these components as well,

226
00:14:16.600 --> 00:14:19.320
are mostly generated by Flutter Flow.

227
00:14:19.320 --> 00:14:21.640
We'll see how they look.

228
00:14:21.640 --> 00:14:24.640
The data layers, the back-end folder

229
00:14:24.640 --> 00:14:30.920
with services for Firebase and also access to API.

230
00:14:30.920 --> 00:14:34.960
And we have a Flutter Flow folder.

231
00:14:34.960 --> 00:14:42.680
And I would say that one of the main goals

232
00:14:42.680 --> 00:14:45.480
from migrating out of the Flutter Flow,

233
00:14:45.480 --> 00:14:51.280
including this migration, is to eventually get completely

234
00:14:51.280 --> 00:14:52.920
rid of this folder.

235
00:14:52.920 --> 00:14:58.960
Because this folder has a lot of dependencies

236
00:14:58.960 --> 00:15:01.200
from Flutter Flow.

237
00:15:00.000 --> 00:15:02.360
by Flutter for maintain libraries

238
00:15:02.360 --> 00:15:05.920
and it's all uses a lot of this structure

239
00:15:05.920 --> 00:15:10.920
that Flutter flow defines as ideal for their projects

240
00:15:11.360 --> 00:15:15.160
but it's not what we think it's ideal for our own project.

241
00:15:15.160 --> 00:15:18.680
So our goal for the future is probably remove

242
00:15:18.680 --> 00:15:21.680
all dependency from this flow folder.

243
00:15:21.680 --> 00:15:24.440
This will probably be done in small steps,

244
00:15:24.440 --> 00:15:27.520
like I said, as we work on different projects

245
00:15:27.520 --> 00:15:28.720
and different features.

246
00:15:30.680 --> 00:15:33.880
Custom code is basically all the custom code

247
00:15:33.880 --> 00:15:38.280
that was generated, that was created inside Flutter flow.

248
00:15:38.280 --> 00:15:40.680
So in Flutter flow, we have the ability

249
00:15:40.680 --> 00:15:44.880
to create specific sections of code that are custom

250
00:15:44.880 --> 00:15:48.320
and this can be called by our components

251
00:15:48.320 --> 00:15:51.560
and all these codes lives inside this folder.

252
00:15:51.560 --> 00:15:55.920
Auth is everything of authentication related

253
00:15:55.920 --> 00:16:00.760
and app state is a legacy global state management

254
00:16:00.760 --> 00:16:02.680
from Flutter flow as well.

255
00:16:02.680 --> 00:16:06.840
So that's it for the main structure

256
00:16:06.840 --> 00:16:10.440
and for the key folders, key files of that.

257
00:16:13.960 --> 00:16:18.960
Now let's move to how we are thinking

258
00:16:21.120 --> 00:16:25.500
in terms of the desired architecture for the app

259
00:16:26.020 --> 00:16:28.540
and then we will see what's current.

260
00:16:29.620 --> 00:16:32.380
Then we see a little bit of how we use also cursor rules

261
00:16:32.380 --> 00:16:36.900
to try to enforce this desired architecture.

262
00:16:36.900 --> 00:16:39.660
And finally, we will see the current state

263
00:16:39.660 --> 00:16:43.820
of the architecture and one example from migrating

264
00:16:43.820 --> 00:16:48.820
from the old architecture, let's say to this newer one.

265
00:16:48.980 --> 00:16:53.980
So very basic, we have three layers in general,

266
00:16:55.940 --> 00:16:58.900
the presentation layer where widgets, pages

267
00:16:58.900 --> 00:17:00.540
and providers live.

268
00:17:00.540 --> 00:17:04.220
We have the domain layers with the logic itself,

269
00:17:04.220 --> 00:17:05.460
with the business logic.

270
00:17:05.460 --> 00:17:09.260
So use cases, entities and the repository interface.

271
00:17:10.300 --> 00:17:15.180
And finally, we have the data layer with calling,

272
00:17:15.180 --> 00:17:18.180
with access to the Firebase slash API

273
00:17:18.180 --> 00:17:22.020
and the implementations for the repositories

274
00:17:22.020 --> 00:17:25.060
for the interface of the repository

275
00:17:25.060 --> 00:17:27.619
that we define it on the domain layer.

276
00:17:30.740 --> 00:17:35.740
So going in more detail of which one,

277
00:17:36.380 --> 00:17:41.380
presentation widgets depend on domain contracts only.

278
00:17:44.300 --> 00:17:47.860
So everything that's on the presentation layer

279
00:17:48.540 --> 00:17:51.060
should only have access to what's on the domain layer.

280
00:17:51.060 --> 00:17:56.060
So that's the idea of avoiding having to add

281
00:17:58.060 --> 00:17:59.740
all the models and all the stuff

282
00:17:59.740 --> 00:18:02.220
and to import everything that's on the data layer

283
00:18:02.220 --> 00:18:03.460
to the presentation layer.

284
00:18:03.460 --> 00:18:07.940
We don't want to create this cross layer interconnection.

285
00:18:07.940 --> 00:18:11.420
We want to keep things as clean and separated as possible.

286
00:18:11.420 --> 00:18:14.180
So presentation layer only communicates

287
00:18:14.180 --> 00:18:17.500
with the logic layer that informs the presentation layer

288
00:18:18.140 --> 00:18:22.660
how it should behave and what information it should show.

289
00:18:22.660 --> 00:18:26.620
And the presentation layer itself is responsible

290
00:18:26.620 --> 00:18:29.580
for deciding how it's going to be shown,

291
00:18:29.580 --> 00:18:31.540
but not what's going to be shown.

292
00:18:31.540 --> 00:18:34.580
And that's the main difference between the two.

293
00:18:34.580 --> 00:18:39.580
So I think we can, I can...

294
00:18:40.100 --> 00:18:43.580
Actually, I will wait until the migration part

295
00:18:43.580 --> 00:18:47.340
to show how it's currently looking on the implementation,

296
00:18:48.180 --> 00:18:50.500
just so we don't take a lot of time

297
00:18:50.500 --> 00:18:52.500
because I have the dentist to talk a lot.

298
00:18:52.500 --> 00:18:55.420
So let's keep things short for this part.

299
00:18:56.820 --> 00:19:00.300
The domain layer defines the business rules

300
00:19:00.300 --> 00:19:04.140
with entities and use case and never,

301
00:19:04.140 --> 00:19:09.140
and we do never import the widgets related to Flutter

302
00:19:10.860 --> 00:19:14.300
or any of the Firebase direct code.

303
00:19:14.300 --> 00:19:15.900
So it's a cleaner layer

304
00:19:15.900 --> 00:19:18.620
with just the application business logic.

305
00:19:19.780 --> 00:19:24.780
And finally, the data layer implements the repositories

306
00:19:25.260 --> 00:19:28.460
that these in turn will talk to the backend

307
00:19:28.460 --> 00:19:31.460
and map the documents to specific entities

308
00:19:31.460 --> 00:19:34.460
that will return be used by the domain layer.

309
00:19:34.460 --> 00:19:38.420
And the domain layer will pass only the information

310
00:19:38.420 --> 00:19:41.820
that needs to be shown back to the presentation layer.

311
00:19:41.820 --> 00:19:46.820
So it's a very straightforward structure.

312
00:19:46.980 --> 00:19:51.980
And like I said, this is the structure we are aiming for.

313
00:19:52.340 --> 00:19:54.340
This is not what we currently have,

314
00:19:54.340 --> 00:19:59.340
but that's the overall desired state for the application.

315
00:20:00.000 --> 00:20:05.000
We have a lot of cursor rules that we use.

316
00:20:05.720 --> 00:20:07.720
And when I say cursor rules,

317
00:20:07.720 --> 00:20:10.360
you can take into account that this can be migrated

318
00:20:10.360 --> 00:20:14.520
to the cloud code SDK with specific rules

319
00:20:14.520 --> 00:20:19.320
or any other type of AI helper that you are using.

320
00:20:20.400 --> 00:20:22.360
Basically, it's the same thing.

321
00:20:22.360 --> 00:20:24.720
It's just a document of text

322
00:20:24.720 --> 00:20:26.600
that highlights what we want.

323
00:20:26.600 --> 00:20:29.360
So the clean architecture,

324
00:20:29.360 --> 00:20:33.040
basically, it's a folder specifying

325
00:20:33.040 --> 00:20:35.840
and spelling out the solid patterns

326
00:20:35.840 --> 00:20:39.080
and how this is applied to our project.

327
00:20:40.120 --> 00:20:43.520
We have one very interesting rule,

328
00:20:43.520 --> 00:20:45.960
which is the Flutter flow migration rule

329
00:20:45.960 --> 00:20:50.960
in order to clearly define what we want

330
00:20:51.600 --> 00:20:55.960
when we are removing Flutter flow dependencies from the app

331
00:20:55.960 --> 00:20:59.280
and what are the things that we want to remove.

332
00:21:01.040 --> 00:21:03.080
And we have some layer,

333
00:21:03.080 --> 00:21:06.560
which is the Flutter best practice

334
00:21:06.560 --> 00:21:11.200
that's basically oriented to better widget composition,

335
00:21:11.200 --> 00:21:16.200
state handling, and single responsibility principle,

336
00:21:16.760 --> 00:21:20.640
which I think it's basically the main thing

337
00:21:20.640 --> 00:21:23.440
when we are thinking in terms of architecture,

338
00:21:23.440 --> 00:21:26.280
especially in the age of AI,

339
00:21:26.280 --> 00:21:30.280
I would say that good architecture

340
00:21:30.280 --> 00:21:34.360
is even more rewarding to have now than before.

341
00:21:34.360 --> 00:21:37.680
Like before it was very important

342
00:21:37.680 --> 00:21:40.400
because we needed someone else

343
00:21:40.400 --> 00:21:43.920
to be able to jump in our code and to find things easily.

344
00:21:43.920 --> 00:21:47.440
And we also wanted to be able to have the architecture

345
00:21:47.440 --> 00:21:49.200
on the back of our minds

346
00:21:49.200 --> 00:21:52.400
and to work with it in a simple manner.

347
00:21:52.400 --> 00:21:55.560
So if you have like a lot of interconnections

348
00:21:55.560 --> 00:21:58.880
and you don't have a pre-established structure,

349
00:21:58.880 --> 00:22:02.160
then you probably aren't able to create

350
00:22:02.160 --> 00:22:06.200
this house of cards in your mind

351
00:22:06.200 --> 00:22:08.480
of how the app should work.

352
00:22:08.480 --> 00:22:11.320
And when you were working,

353
00:22:11.320 --> 00:22:15.280
you probably would make decisions that were not aligned

354
00:22:15.280 --> 00:22:17.000
with the original architecture

355
00:22:17.000 --> 00:22:18.880
or with the desired architecture.

356
00:22:19.880 --> 00:22:24.880
And I think a lot of this go back

357
00:22:26.000 --> 00:22:28.520
to the single responsibility principle

358
00:22:28.520 --> 00:22:33.160
that now with the age of AI is even more important

359
00:22:33.160 --> 00:22:38.160
where since we have limited context windows for LLMs

360
00:22:41.000 --> 00:22:45.360
and even like 1 million context windows that we have now,

361
00:22:46.240 --> 00:22:48.520
it's not actually 1 million

362
00:22:49.160 --> 00:22:52.320
because if you are going to try to add more stuff

363
00:22:52.320 --> 00:22:57.120
and go to the max amount of context that you can use,

364
00:22:57.120 --> 00:23:00.240
the model starts to get number.

365
00:23:00.240 --> 00:23:04.720
So the idea is that you want to create an architecture

366
00:23:04.720 --> 00:23:08.000
that you need to feed as little as possible

367
00:23:08.000 --> 00:23:11.120
of the architecture, of the widgets, of the files.

368
00:23:11.120 --> 00:23:13.860
You need to feed a little as possible

369
00:23:13.860 --> 00:23:16.280
to be able to get the model

370
00:23:16.280 --> 00:23:19.760
to understand your architecture

371
00:23:19.760 --> 00:23:22.560
and to be able to follow through the changes

372
00:23:22.560 --> 00:23:26.920
without exactly breaking into more small files

373
00:23:26.920 --> 00:23:28.720
rather than fewer larger ones.

374
00:23:28.720 --> 00:23:33.000
That's the best deal of the air for it.

375
00:23:33.000 --> 00:23:35.280
You want to have smaller files

376
00:23:35.280 --> 00:23:37.840
because they are easy to work with

377
00:23:37.840 --> 00:23:39.720
even from a human standpoint,

378
00:23:39.720 --> 00:23:42.540
but also now from a machine standpoint.

379
00:23:43.620 --> 00:23:45.840
So very important to keep this in mind.

380
00:23:46.440 --> 00:23:51.440
Now let's go to the most interesting part in my opinion,

381
00:23:59.800 --> 00:24:03.160
which is this migration case study

382
00:24:03.160 --> 00:24:05.320
for the groups community feed.

383
00:24:05.320 --> 00:24:07.280
So the groups community feed

384
00:24:07.280 --> 00:24:10.680
is basically the main screen of our application.

385
00:24:10.680 --> 00:24:14.720
It's the feed that has all the communication

386
00:24:14.720 --> 00:24:17.040
that's happening, all the posts,

387
00:24:17.040 --> 00:24:20.680
all the lives that were recorded or replaced.

388
00:24:20.680 --> 00:24:25.680
So everything that's important, not important,

389
00:24:27.000 --> 00:24:31.040
but everything that's happening inside the apps

390
00:24:31.040 --> 00:24:33.920
tends to go into the community feed somehow.

391
00:24:35.840 --> 00:24:38.280
Exactly, that's very important.

392
00:24:38.280 --> 00:24:40.600
Lucian just mentioned one thing very important

393
00:24:40.600 --> 00:24:42.820
here on the chat,

394
00:24:42.820 --> 00:24:47.820
which is properly named functions, classes, and variables.

395
00:24:48.120 --> 00:24:52.120
And it's funny because that's even a meme,

396
00:24:52.120 --> 00:24:56.240
like we take like X amount of time to create something

397
00:24:56.240 --> 00:25:00.200
and then 2X the amount of time to name the variable.

398
00:25:00.000 --> 00:25:07.920
for it and I think this is very true and I think this from someone who maybe hasn't worked with

399
00:25:07.920 --> 00:25:15.280
code could think that this is useless and but it's one of the most important things that that we have

400
00:25:15.280 --> 00:25:22.000
is like to have clear functions, definitions, to have clear named classes, to have clear named

401
00:25:22.000 --> 00:25:31.040
variables. It makes your life easier and it makes the AI life easier because then, for instance,

402
00:25:32.400 --> 00:25:37.520
you can have just the definition of the function, meaning you have just the information,

403
00:25:37.520 --> 00:25:43.520
the type of the function, what it expects as a parameter and what's the expected output

404
00:25:44.240 --> 00:25:49.520
and with all the information, with only the contract information, you can make decisions

405
00:25:49.520 --> 00:25:59.360
about it and that's the ideal image or the ideal point that we want to have.

406
00:25:59.360 --> 00:26:05.840
We want to be able to just look at the name of the function, the parameters that it needs and

407
00:26:05.840 --> 00:26:13.840
what's the return and we want to be able to, from this, take this, use it and take into account

408
00:26:14.560 --> 00:26:23.760
into our decisions just by the contracts. So now going back to the migration case study,

409
00:26:25.040 --> 00:26:35.680
like I said, why this page? Why we refactor it? So first, it had 1094 lines of code and for

410
00:26:36.560 --> 00:26:46.080
let's say just a feed, it was a very big component and it was basically all

411
00:26:46.080 --> 00:26:51.920
generated by FlutterFlow, so it was a key component from the app and all the code in it was basically

412
00:26:51.920 --> 00:26:59.200
generated by FlutterFlow, so this was a very strong motivation for this change

413
00:27:00.000 --> 00:27:10.080
and everything was built inside the build function of the widget, which is a very poor practice,

414
00:27:10.080 --> 00:27:18.640
like when you read the build function of the app, it should be quick, clean and easy to read and

415
00:27:18.640 --> 00:27:23.680
with just a glance, you need to understand, hey, by reading the build function of a widget,

416
00:27:23.760 --> 00:27:30.080
I want to be able to imagine what this widget will look like and when you have like

417
00:27:31.520 --> 00:27:39.040
a thousand lines of code, this is not possible because you have paddings, you have other widgets

418
00:27:39.040 --> 00:27:46.240
intertwined with each other, so I will show the before and after for you guys to

419
00:27:46.240 --> 00:27:56.000
be able to have a more concrete example, but the monolithic build, they have dependency on the

420
00:27:56.000 --> 00:28:04.160
FlutterFlow app state management and also inline Firebase queries were all things that were

421
00:28:04.160 --> 00:28:14.960
happening inside this component that we got rid of. The refactor component now has 429 lines,

422
00:28:14.960 --> 00:28:23.200
so less than half and has helper methods, extracted sections and testable streams

423
00:28:24.160 --> 00:28:32.240
and a few of the highlights was, first, the UI was sliced in different focused widgets, so instead

424
00:28:32.240 --> 00:28:38.720
of having one big widget, we broke this down into feature content section, category filter section,

425
00:28:38.720 --> 00:28:45.120
create post section, post list section, all listed under the group components page,

426
00:28:45.120 --> 00:28:55.840
group components folder. We also centralized the logic of the life cycle inside the initialized

427
00:28:55.840 --> 00:29:03.920
page data and show update dialog if needed, so as you can see, just by reading the function, you can

428
00:29:04.560 --> 00:29:12.480
imagine what they do. One is for initializing the page data, so pretty self-explanatory,

429
00:29:12.480 --> 00:29:19.360
and the show update dialog if needed is basically it. We have a dialog that asks the user to update

430
00:29:19.360 --> 00:29:26.080
the app if they need to update it instead of scattered around the schedule by their callbacks

431
00:29:26.080 --> 00:29:34.960
that it's a thing that Flutter Flows relies a lot. And we have a model for delegating the

432
00:29:36.400 --> 00:29:44.720
updates to the selected category with a local set state, avoiding the global state churn because

433
00:29:44.720 --> 00:29:52.880
it was previously dependent on that app state of that Flutter Flow app state management system,

434
00:29:52.880 --> 00:29:59.920
and we replaced it with the simpler option that we have with the set state, so this was a very

435
00:30:00.000 --> 00:30:04.920
Very interesting change as well, and it helped a lot.

436
00:30:04.920 --> 00:30:09.840
So the difference walks through.

437
00:30:09.840 --> 00:30:12.200
Let's say, so pre-reflector defeat

438
00:30:12.200 --> 00:30:16.200
used a paged list view with paging controller,

439
00:30:16.200 --> 00:30:19.800
mixing Firestore queries with widget concerns,

440
00:30:19.800 --> 00:30:20.920
which is very bad.

441
00:30:20.920 --> 00:30:23.520
Like, when we are in the presentation layer,

442
00:30:23.520 --> 00:30:28.680
we want to be seeing just UI-related stuff.

443
00:30:28.680 --> 00:30:32.680
We don't want to be seeing, like, queries and logic,

444
00:30:32.680 --> 00:30:34.320
and that was what was happening.

445
00:30:37.400 --> 00:30:40.280
And Bruce?

446
00:30:40.280 --> 00:30:41.120
No, this is great.

447
00:30:41.120 --> 00:30:42.880
I was going to say, like, maybe you could

448
00:30:42.880 --> 00:30:47.440
dig into that a little bit, because so the, like,

449
00:30:47.440 --> 00:30:50.120
backstory on this particular group page

450
00:30:50.120 --> 00:30:54.280
had been a pain point for probably a year or two.

451
00:30:54.280 --> 00:30:56.520
It's like, we're making a social media app.

452
00:30:56.520 --> 00:30:57.360
This is the feed.

453
00:30:57.360 --> 00:31:00.160
It is kind of like the whole app in one thing.

454
00:31:00.160 --> 00:31:03.560
And we've probably spent months and probably

455
00:31:03.560 --> 00:31:07.880
over, like, a few hundred hours optimizing this page

456
00:31:07.880 --> 00:31:09.160
to get it to work better.

457
00:31:09.160 --> 00:31:11.440
And so we're inside of Flutter Flow, that is.

458
00:31:11.440 --> 00:31:14.440
And so once we moved it out of Flutter Flow, obviously weird.

459
00:31:14.440 --> 00:31:16.120
I mean, I think this maybe, what,

460
00:31:16.120 --> 00:31:19.080
did it take, like, a week or so?

461
00:31:19.080 --> 00:31:19.720
Yeah.

462
00:31:19.720 --> 00:31:21.680
Yeah, it wasn't a long time.

463
00:31:21.680 --> 00:31:25.640
So had we known this sooner, we could

464
00:31:25.680 --> 00:31:27.920
have pulled it out of Flutter Flow sooner

465
00:31:27.920 --> 00:31:30.440
and maybe got some better results faster.

466
00:31:30.440 --> 00:31:32.320
And it really comes, just when you're

467
00:31:32.320 --> 00:31:36.760
using these low-code tools, it does take,

468
00:31:36.760 --> 00:31:38.480
there's so many layers of abstraction.

469
00:31:38.480 --> 00:31:40.520
So you just end up looking at the design.

470
00:31:40.520 --> 00:31:42.280
And we had some pretty smart people,

471
00:31:42.280 --> 00:31:45.640
including yourself, like, all trying to be in Flutter Flow,

472
00:31:45.640 --> 00:31:47.480
trying to fix certain things.

473
00:31:47.480 --> 00:31:49.760
But once we got it out of there, and we kind of

474
00:31:49.760 --> 00:31:53.320
broke all these pieces into kind of getting back closer,

475
00:31:53.920 --> 00:31:56.920
basically losing layers of abstraction,

476
00:31:56.920 --> 00:31:59.640
we could get more control of it.

477
00:31:59.640 --> 00:32:02.200
And so this all looks better.

478
00:32:02.200 --> 00:32:05.560
You said it went from 1,100 lines to 400 lines.

479
00:32:05.560 --> 00:32:06.240
That's great.

480
00:32:06.240 --> 00:32:08.800
The other thing is it fixed so many errors.

481
00:32:08.800 --> 00:32:11.400
It wasn't even working well.

482
00:32:11.400 --> 00:32:12.160
It was slow.

483
00:32:12.160 --> 00:32:13.520
It was laggy.

484
00:32:13.520 --> 00:32:15.400
We had a bunch of weird logic, where

485
00:32:15.400 --> 00:32:17.560
you had to basically post, and then you

486
00:32:17.560 --> 00:32:18.960
wanted to immediately see your post,

487
00:32:18.960 --> 00:32:20.360
or if someone liked your post, it

488
00:32:20.360 --> 00:32:22.720
needed sort of instantaneous updates.

489
00:32:22.720 --> 00:32:24.200
But also, it's an infinite scroll.

490
00:32:24.200 --> 00:32:28.080
There could be thousands of lines of posts in this feed.

491
00:32:28.080 --> 00:32:31.120
So there's lots of little, weird, quirky things.

492
00:32:31.120 --> 00:32:33.160
Basically, it was like an infinite scroll.

493
00:32:33.160 --> 00:32:36.320
But also, we needed to have dynamic heights on the images,

494
00:32:36.320 --> 00:32:38.120
because we have, sometimes there's an image,

495
00:32:38.120 --> 00:32:40.280
sometimes there's text, sometimes there's a video.

496
00:32:40.280 --> 00:32:43.920
So it's a very complex set of parameters.

497
00:32:43.920 --> 00:32:47.160
So not only did we make it much simpler to work on,

498
00:32:47.160 --> 00:32:49.440
and the code's cleaner, it actually works,

499
00:32:49.440 --> 00:32:51.720
if you can imagine that, now that it's built right.

500
00:32:51.720 --> 00:32:54.920
It actually is much faster, it's more instantaneous,

501
00:32:54.920 --> 00:32:57.320
and it's much more reliable now that we've cleaned that up.

502
00:32:57.320 --> 00:33:00.480
So I just want to give some context from the end user

503
00:33:00.480 --> 00:33:01.800
experience as well.

504
00:33:01.800 --> 00:33:03.360
So nice.

505
00:33:03.360 --> 00:33:04.720
You can keep going.

506
00:33:04.720 --> 00:33:05.240
Perfect.

507
00:33:05.240 --> 00:33:08.520
And I think this is what Bruce said,

508
00:33:08.520 --> 00:33:11.120
about layers of abstraction.

509
00:33:11.120 --> 00:33:14.120
I think this is very, very important.

510
00:33:14.120 --> 00:33:18.120
We even were discussing inside our Slack channel

511
00:33:18.160 --> 00:33:25.880
about an article regarding the great collapse of software

512
00:33:25.880 --> 00:33:28.040
quality, or something like that.

513
00:33:28.040 --> 00:33:32.040
And basically, it's an article showing

514
00:33:32.040 --> 00:33:34.960
a lot of problems with the current state of how

515
00:33:34.960 --> 00:33:38.680
software development's working right now, especially with AI.

516
00:33:38.680 --> 00:33:41.880
But I think one of the points that's important for us

517
00:33:41.880 --> 00:33:47.440
right now is this, of the many layers of abstraction.

518
00:33:47.440 --> 00:33:50.800
I like to think about it, of layers of abstraction,

519
00:33:50.800 --> 00:33:55.840
in terms of, it's almost a lever connected to another lever,

520
00:33:55.840 --> 00:33:58.400
and then another lever, and then another lever.

521
00:33:58.400 --> 00:34:01.560
And then you are on the top, pulling one of these levers,

522
00:34:01.560 --> 00:34:06.520
and these go, like, triggering all the levers

523
00:34:06.520 --> 00:34:08.159
from the layers below.

524
00:34:08.159 --> 00:34:12.000
And yeah, it's easier than, it's,

525
00:34:12.000 --> 00:34:18.480
let's say, easier and faster to move the top layer lever than

526
00:34:18.480 --> 00:34:24.000
going down and working on the behind of the scenes,

527
00:34:24.000 --> 00:34:25.000
let's say.

528
00:34:25.000 --> 00:34:28.440
But this also comes with a lot of trade-offs,

529
00:34:28.440 --> 00:34:32.639
especially in terms of having less control over what

530
00:34:32.639 --> 00:34:34.239
you are building.

531
00:34:34.239 --> 00:34:41.040
And also, and which I think it's the most risky one,

532
00:34:41.040 --> 00:34:44.199
is you actually don't know what's happening.

533
00:34:44.199 --> 00:34:47.120
So that's one thing with FlutterFlow.

534
00:34:47.120 --> 00:34:50.080
We can know so much.

535
00:34:50.080 --> 00:34:55.520
Like, we can understand so much, to a point

536
00:34:55.520 --> 00:35:01.320
that if you want to understand more, it's more.

537
00:35:00.000 --> 00:35:04.440
are worth it to just migrate out of it and do it by yourself,

538
00:35:04.440 --> 00:35:08.400
then try to understand their form of abstraction

539
00:35:08.400 --> 00:35:11.080
and work with their abstraction layer.

540
00:35:11.080 --> 00:35:14.440
So that's one thing we actually learned by doing

541
00:35:14.440 --> 00:35:17.760
and by exploring, because we really took the Flutter

542
00:35:17.760 --> 00:35:19.160
flow to the limit.

543
00:35:19.160 --> 00:35:20.840
I really believe that.

544
00:35:20.840 --> 00:35:22.880
We did a great job with it.

545
00:35:22.880 --> 00:35:26.720
And it was a very helpful tool.

546
00:35:26.720 --> 00:35:30.440
It really makes things faster on the beginning,

547
00:35:30.440 --> 00:35:33.640
especially because all this started before.

548
00:35:33.640 --> 00:35:37.200
We have tools like AI to help us with accelerating

549
00:35:37.200 --> 00:35:39.440
some part of the beauty.

550
00:35:39.440 --> 00:35:43.080
But now that times change it, and also

551
00:35:43.080 --> 00:35:46.840
that Tribe itself is a more robust application,

552
00:35:46.840 --> 00:35:49.960
we kind of grew out of Flutter flow.

553
00:35:49.960 --> 00:35:53.120
And we kind of decided that we needed

554
00:35:53.120 --> 00:35:57.200
to have fewer layers of abstraction between us

555
00:35:57.200 --> 00:35:59.400
and what we really wanted to do.

556
00:35:59.400 --> 00:36:02.000
So that's an important thing to keep in mind,

557
00:36:02.000 --> 00:36:05.840
that every time that you are adding a layer of abstraction,

558
00:36:05.840 --> 00:36:09.120
meaning if you are adding a package that

559
00:36:09.120 --> 00:36:12.680
will be doing something for you, this is a layer of abstraction.

560
00:36:12.680 --> 00:36:16.680
And this is fine to a point, but you really

561
00:36:16.680 --> 00:36:17.840
want to think about it.

562
00:36:17.840 --> 00:36:20.240
Like, for instance, this page, we

563
00:36:20.280 --> 00:36:24.200
were using an external dependency

564
00:36:24.200 --> 00:36:28.960
to have the infinite scroll, to have

565
00:36:28.960 --> 00:36:31.560
a paginated infinite scroll.

566
00:36:31.560 --> 00:36:36.160
This component, the way Flutter flow implemented,

567
00:36:36.160 --> 00:36:39.880
it was by actually importing an external dependency

568
00:36:39.880 --> 00:36:43.080
of another developer who built this component,

569
00:36:43.080 --> 00:36:46.840
and we were reusing it, which is fine.

570
00:36:46.840 --> 00:36:49.720
I think it's very useful to have this kind of tools.

571
00:36:49.720 --> 00:36:53.800
But it's an independence in the end.

572
00:36:53.800 --> 00:36:59.000
So you don't know exactly how the developer built.

573
00:36:59.000 --> 00:37:01.520
You don't know when they are going to update it.

574
00:37:01.520 --> 00:37:03.840
You don't know if they are going to update it.

575
00:37:03.840 --> 00:37:06.280
So every time that you are adding new stuff,

576
00:37:06.280 --> 00:37:08.600
you are adding these layers of abstractions,

577
00:37:08.600 --> 00:37:10.880
you need to take this into account.

578
00:37:10.880 --> 00:37:14.120
And in this specific case, we opted

579
00:37:14.120 --> 00:37:16.880
to remove this dependence completely

580
00:37:16.880 --> 00:37:20.360
and to build our own pagination,

581
00:37:20.360 --> 00:37:23.880
our paginated infinite scroller from the scratch.

582
00:37:23.880 --> 00:37:26.840
And it was one of the best things we could have done.

583
00:37:26.840 --> 00:37:30.960
It was like, it took, I think, two or three hours maybe.

584
00:37:30.960 --> 00:37:36.080
But the overall experience was a lot faster and a lot easier

585
00:37:36.080 --> 00:37:39.520
to use from a user standpoint and also

586
00:37:39.520 --> 00:37:41.040
from a developer standpoint.

587
00:37:41.040 --> 00:37:46.160
So yeah, it's worth to keep an eye on it.

588
00:37:46.160 --> 00:37:48.880
Sometimes you have to balance this trade

589
00:37:48.880 --> 00:37:52.280
between ease of use, fast, and the performance

590
00:37:52.280 --> 00:37:55.040
and the control you have over the code.

591
00:37:55.040 --> 00:37:55.560
Nice.

592
00:37:55.560 --> 00:37:56.560
That's awesome.

593
00:37:56.560 --> 00:37:58.760
I know you got about 5 or 10 minutes.

594
00:37:58.760 --> 00:38:01.880
I don't know what you wanted to hit on the last little video.

595
00:38:01.880 --> 00:38:04.760
This is super helpful to kind of see this.

596
00:38:04.760 --> 00:38:07.440
Or if you guys, Lucho and Ira, anyone on the team

597
00:38:07.440 --> 00:38:12.160
want to see anything specific on this,

598
00:38:12.160 --> 00:38:15.800
what else did you want to touch on and jump in?

599
00:38:16.560 --> 00:38:20.880
I will kind of just wrap this part.

600
00:38:20.880 --> 00:38:25.400
Actually, this whole slide right here

601
00:38:25.400 --> 00:38:28.400
is basically a summary of what I did.

602
00:38:28.400 --> 00:38:30.960
So I will just touch these five points.

603
00:38:30.960 --> 00:38:34.720
And then we go to cursor to EDI just

604
00:38:34.720 --> 00:38:37.240
to see how this is implemented, in fact.

605
00:38:37.240 --> 00:38:41.000
So in terms of the migration itself,

606
00:38:41.000 --> 00:38:43.280
here is a small playbook that we have.

607
00:38:43.280 --> 00:38:47.480
It's map the page, identify responsibilities, navigation,

608
00:38:47.480 --> 00:38:51.720
filters, content, and draw a desired widget tree.

609
00:38:51.720 --> 00:38:54.120
And this is really, you can draw it.

610
00:38:54.120 --> 00:38:56.160
You can take just a piece of paper

611
00:38:56.160 --> 00:38:59.280
and write it down and see, hey, I'm satisfied

612
00:38:59.280 --> 00:39:01.760
with how this should look.

613
00:39:01.760 --> 00:39:06.440
And then you have a goal in mind in terms of the widget tree

614
00:39:06.440 --> 00:39:08.080
itself.

615
00:39:08.080 --> 00:39:10.840
Then you extract the components.

616
00:39:10.840 --> 00:39:11.840
You map the components.

617
00:39:11.840 --> 00:39:16.360
Then you extract them out of that big chunk of code.

618
00:39:16.360 --> 00:39:18.440
You isolate the state management.

619
00:39:18.440 --> 00:39:23.680
So we replace the FFF state with scoped providers

620
00:39:23.680 --> 00:39:27.880
or any other state management alternative

621
00:39:27.880 --> 00:39:31.480
that you think is suitable for that component.

622
00:39:31.480 --> 00:39:36.240
You move the logic out by removing the five-star queries

623
00:39:36.240 --> 00:39:39.640
or any type of logic that's embedded into the presentation

624
00:39:39.640 --> 00:39:41.360
layer.

625
00:39:41.360 --> 00:39:44.760
And then you can, in the five and last step,

626
00:39:44.760 --> 00:39:48.920
is that you can add widgets or unit tests

627
00:39:48.920 --> 00:39:53.440
around the new components before deleting the FFF original.

628
00:39:53.440 --> 00:39:55.320
So that's something we also do.

629
00:39:55.320 --> 00:39:58.960
We keep the original components in the code base for a while,

630
00:39:58.960 --> 00:40:01.600
for like three, four months.

631
00:40:00.000 --> 00:40:05.920
for weeks until we see that everything is okay, that it's working properly, and then we delete

632
00:40:05.920 --> 00:40:13.760
the old components. So, key takeaways. Migration will happen incrementally. Keep the generated

633
00:40:13.760 --> 00:40:21.680
widgets around until priority is proven. Aim to shrink files and reduce the cyclomatic complexity

634
00:40:21.680 --> 00:40:29.440
on each pass. I even added a link here to this part because I think it's very useful to think

635
00:40:30.880 --> 00:40:36.880
to have this in mind when you are thinking in terms of code because it allows to visually see

636
00:40:36.880 --> 00:40:43.600
the complexity of your code. So, I really like this. So, basically, every time that you have

637
00:40:43.600 --> 00:40:55.920
a decision, you create new nodes on your cyclomatic tree, let's say. So, for instance,

638
00:40:55.920 --> 00:41:03.520
on this case, they have this very simple example of code, and here is how the complex,

639
00:41:05.120 --> 00:41:13.840
the cyclomatic complexity is drawn for this case. We have, I think we have one,

640
00:41:14.800 --> 00:41:20.160
oh, this one I like to use it. So, let me open it.

641
00:41:23.760 --> 00:41:33.520
So, basically, it's a quick formula that you take your code and you pass it through, and it will

642
00:41:33.520 --> 00:41:41.920
give you a value that you more or less can estimate the complexity of that code. So,

643
00:41:41.920 --> 00:41:48.960
this is a mathematical way of measuring code complexity. So, it's very useful because then

644
00:41:48.960 --> 00:41:54.160
you can basically, this is the kind of thing that you can take and feed to LLM. It will analyze the

645
00:41:54.160 --> 00:42:00.400
code and give you a value, and then you can compare it to the value from your refactor

646
00:42:00.400 --> 00:42:06.960
component. So, this is a good thing to keep in mind. It's useful, too, to have while evaluating

647
00:42:06.960 --> 00:42:17.360
code complexity. And finally, clean architecture folders are the destination and refactor widgets

648
00:42:17.360 --> 00:42:25.040
are the bridge. So, now let's take this last couple minutes just to see how this is looking

649
00:42:25.040 --> 00:42:34.240
in practice. So, first of all, let me show the original component. Let me change the screen I'm

650
00:42:34.240 --> 00:42:47.040
sharing right now. Okay. Perfect. So, this is the original component. This is the widget component.

651
00:42:49.280 --> 00:42:57.920
So, as you can see, we have this state. It's necessary for every widget, but I think the

652
00:42:57.920 --> 00:43:05.280
most important part here to look at is this build function that we have. So,

653
00:43:05.280 --> 00:43:12.720
the build function is basically the main function of every widget. And if I close this,

654
00:43:14.000 --> 00:43:20.000
you see everything is inside the build function. So, this is crazy, to give many

655
00:43:20.000 --> 00:43:28.560
things. Because once you open this page, you really have to look at all this to understand

656
00:43:29.120 --> 00:43:35.760
what this page is doing. Like, what are components of it? How it's laid down? What's the logic behind

657
00:43:35.760 --> 00:43:46.480
it? And it's just and even like here we have like responsive behavior. Like, if it's on

658
00:43:46.480 --> 00:43:54.080
a certain size, we are making things different. And we also have like the logic here

659
00:43:54.720 --> 00:44:03.040
embedded into the widget. And we also have like let me see if I can find

660
00:44:06.880 --> 00:44:14.800
like you have dependencies on buttons from Flutterflow. Like, why do we even need the FF

661
00:44:14.800 --> 00:44:18.880
button widget? It's just a button. We don't need it to be from Flutterflow. So,

662
00:44:18.880 --> 00:44:24.960
this is useful for the Flutterflow itself to reuse its components, but it's not for us anymore.

663
00:44:24.960 --> 00:44:32.000
So, this one example. And as you can see, overall, it's just very difficult to read,

664
00:44:32.000 --> 00:44:39.520
very difficult to understand what's happening. And it is a very chunky piece of code. And

665
00:44:39.680 --> 00:44:48.240
let's just let's see now how we got this a little better. So, this is the refactor component.

666
00:44:48.800 --> 00:44:57.600
And this is the build function for it. So, a huge difference. And it's easier to read.

667
00:44:57.600 --> 00:44:59.680
You can come here and just see, hey, we have

668
00:45:00.000 --> 00:45:05.000
a FAB, if the FAB is expanded, we have a different,

669
00:45:06.100 --> 00:45:07.760
we show it or not.

670
00:45:08.740 --> 00:45:13.740
We have also a drawer, a app bar and we have a body

671
00:45:14.020 --> 00:45:18.260
and we have the FAB, the floating action button

672
00:45:18.260 --> 00:45:20.740
that's associated with that screen.

673
00:45:20.740 --> 00:45:23.000
So let's see what's on the body.

674
00:45:23.000 --> 00:45:25.960
We can come here and here is the body function.

675
00:45:25.960 --> 00:45:30.560
Like I said, very small, very clean, easy to read.

676
00:45:30.560 --> 00:45:33.200
I really like to have like this helper function.

677
00:45:33.200 --> 00:45:37.640
So if we come here, we just literally read.

678
00:45:37.640 --> 00:45:40.240
So we have a top web nav,

679
00:45:40.240 --> 00:45:42.000
then we have the group navigation,

680
00:45:42.000 --> 00:45:45.140
then we have the main component and we have the bottom bar.

681
00:45:45.140 --> 00:45:49.040
We can click here and then we go to the main contents.

682
00:45:49.040 --> 00:45:50.360
Let's see what's there.

683
00:45:50.360 --> 00:45:52.800
So we have a sidebar, nice.

684
00:45:52.800 --> 00:45:54.680
We have the main content column.

685
00:45:54.680 --> 00:45:56.880
Let's see what's on the main content column.

686
00:45:56.880 --> 00:45:58.000
It's right here.

687
00:45:58.000 --> 00:46:01.320
And here's the chunk of the build of the app.

688
00:46:01.320 --> 00:46:04.600
So even here, it's easier to read

689
00:46:04.600 --> 00:46:08.320
because we have separated it in different sections.

690
00:46:08.320 --> 00:46:10.800
So we have the feature content section.

691
00:46:10.800 --> 00:46:14.080
So we have a feature contents widget.

692
00:46:14.080 --> 00:46:16.680
We have the category filter section.

693
00:46:16.680 --> 00:46:19.800
And finally we have the post list section.

694
00:46:19.800 --> 00:46:23.020
So in just, and also you have the create post section,

695
00:46:23.060 --> 00:46:26.060
which just visible depending on the float action button

696
00:46:30.820 --> 00:46:32.780
or if the user presses the button.

697
00:46:32.780 --> 00:46:37.780
But as you can see, even with like this chunkier component,

698
00:46:38.380 --> 00:46:42.540
we just can scan it and we can see, okay,

699
00:46:42.540 --> 00:46:45.540
that's more or less how it will look like

700
00:46:45.540 --> 00:46:50.160
or that's what this page has as a content.

701
00:46:50.960 --> 00:46:53.440
And if I go here into the post list section,

702
00:46:53.440 --> 00:46:57.900
which is kind of the biggest thing I believe here,

703
00:46:57.900 --> 00:47:01.320
then it's on a separate page completely.

704
00:47:01.320 --> 00:47:04.240
That's one of the things that makes it easier.

705
00:47:04.240 --> 00:47:07.680
So if I'm working just on the post section

706
00:47:07.680 --> 00:47:09.800
and I don't need anything else on the page,

707
00:47:09.800 --> 00:47:14.800
I can fit just this file to the LLM for instance,

708
00:47:14.960 --> 00:47:17.160
or I can look at just this file

709
00:47:17.160 --> 00:47:21.400
and this makes my life a lot easier to give my intent.

710
00:47:21.400 --> 00:47:26.400
So you can see just, we have like the helpers functions

711
00:47:28.440 --> 00:47:30.200
here on top.

712
00:47:30.200 --> 00:47:35.200
And if we go here, we also have by the end of the file,

713
00:47:36.620 --> 00:47:39.600
here is the built component again.

714
00:47:39.600 --> 00:47:41.520
Here is the build content.

715
00:47:41.520 --> 00:47:43.920
Here is how it's being built.

716
00:47:43.920 --> 00:47:45.880
So we have a loader.

717
00:47:45.880 --> 00:47:50.760
Then we have the placeholder if the empty state,

718
00:47:50.760 --> 00:47:52.840
basically, if there's no posts.

719
00:47:52.840 --> 00:47:56.320
And then we have a list view with infinite scroll,

720
00:47:56.320 --> 00:47:59.240
which is the list view that we built from zero.

721
00:47:59.240 --> 00:48:03.400
So if we come here and we go to our pre-refactor component,

722
00:48:04.960 --> 00:48:09.960
we were imparting this infinite scroll pagination

723
00:48:11.100 --> 00:48:13.120
and we are not anymore.

724
00:48:13.120 --> 00:48:14.640
We don't need this anymore.

725
00:48:14.640 --> 00:48:17.360
And we are not relying on the external dependence

726
00:48:17.360 --> 00:48:19.480
to build like the key part of our app.

727
00:48:19.480 --> 00:48:22.280
So this is a very important win

728
00:48:22.280 --> 00:48:25.320
that we've got out of this refactor.

729
00:48:26.400 --> 00:48:31.400
And yeah, I think actually we are kind of approaching

730
00:48:31.880 --> 00:48:36.880
the end of time, but I think this is a good overview

731
00:48:38.120 --> 00:48:39.680
of how we are thinking of it

732
00:48:39.680 --> 00:48:41.960
and how we are breaking things down

733
00:48:41.960 --> 00:48:46.160
and how we are making it easier for us to give maintenance

734
00:48:46.160 --> 00:48:50.880
and also making it faster, better performance

735
00:48:50.880 --> 00:48:54.200
and just better overall.

736
00:48:54.200 --> 00:48:57.400
So yeah, I think that's a wrap.

737
00:48:57.400 --> 00:49:00.320
Now I want to hear if you guys have any questions,

738
00:49:00.320 --> 00:49:02.920
if you guys want to take a look at anything specifically,

739
00:49:02.920 --> 00:49:05.120
but that's it for my side.

740
00:49:06.040 --> 00:49:06.960
That's awesome.

741
00:49:06.960 --> 00:49:09.380
Yeah, and so, you know, on a practical,

742
00:49:09.380 --> 00:49:10.960
you guys can drop any comments if you have them

743
00:49:10.960 --> 00:49:11.800
or we'll wrap it up.

744
00:49:12.640 --> 00:49:14.960
But, you know, this was something that,

745
00:49:16.320 --> 00:49:18.240
you know, I said a few hundred hours,

746
00:49:18.240 --> 00:49:21.440
like that translates to tens of thousands of dollars, right?

747
00:49:21.440 --> 00:49:22.680
If not more.

748
00:49:22.680 --> 00:49:25.800
And so building it much now,

749
00:49:25.800 --> 00:49:26.840
of course we had to kind of iterate

750
00:49:26.840 --> 00:49:29.000
and figure out all these things in pieces,

751
00:49:29.000 --> 00:49:32.600
but now that we're at a lot larger scale,

752
00:49:32.600 --> 00:49:35.800
like this, you know, these little inefficiencies

753
00:49:35.800 --> 00:49:38.440
are like, you know, making a huge difference to cost

754
00:49:38.440 --> 00:49:40.840
and ultimately the experience of our customers,

755
00:49:40.880 --> 00:49:42.440
making sure it's a lot, lot faster.

756
00:49:42.440 --> 00:49:46.880
So we'll have a part two or part three of this,

757
00:49:46.880 --> 00:49:48.160
where we have Lucian talk about

758
00:49:48.160 --> 00:49:51.240
how we're removing all the Firebase out of this code

759
00:49:51.240 --> 00:49:54.120
and getting it over to SQL and API

760
00:49:54.120 --> 00:49:56.440
and using our totally different backend.

761
00:49:56.440 --> 00:49:57.920
But it'll kind of,

762
00:49:57.920 --> 00:50:00.360
it'll cool to see kind of the iterations of the.

763
00:50:00.000 --> 00:50:02.040
the code, first getting it cleaned up,

764
00:50:02.040 --> 00:50:03.800
because now we can actually work with it.

765
00:50:03.800 --> 00:50:05.280
And that's one thing I would highly

766
00:50:05.280 --> 00:50:08.080
recommend anyone who's doing any AI coding.

767
00:50:08.080 --> 00:50:12.080
I recently was refactoring another part of the Flutter app

768
00:50:12.080 --> 00:50:15.400
last week on the Create Post section.

769
00:50:15.400 --> 00:50:19.000
And basically, it was just struggling.

770
00:50:19.000 --> 00:50:22.600
It was about 1,500 or 2,000 lines of code.

771
00:50:22.600 --> 00:50:24.720
And it just was not getting things done.

772
00:50:24.720 --> 00:50:25.880
So at first, I just stopped.

773
00:50:25.880 --> 00:50:29.080
And for 30 minutes, we just totally refactored the entire

774
00:50:29.080 --> 00:50:31.040
code, broke it into seven different pages,

775
00:50:31.040 --> 00:50:35.600
seven different files, pulled common things out,

776
00:50:35.600 --> 00:50:37.280
and made it much, much easier to work on.

777
00:50:37.280 --> 00:50:40.160
So it only had maybe three or four files

778
00:50:40.160 --> 00:50:43.320
that were a few hundred lines each, if not that.

779
00:50:43.320 --> 00:50:46.080
And all of a sudden, it just became so much more reliable.

780
00:50:46.080 --> 00:50:48.000
And then I could actually start working on it.

781
00:50:48.000 --> 00:50:51.160
So if you're getting stuck on these AI things,

782
00:50:51.160 --> 00:50:53.920
take time, fix the code, clean it up,

783
00:50:53.920 --> 00:50:55.880
make sure it's logical.

784
00:50:55.880 --> 00:50:58.120
And this is true if I was working on something

785
00:50:58.120 --> 00:50:59.080
and I was handing it to Jonathan,

786
00:50:59.080 --> 00:51:01.600
or Jonathan was handing it to someone else on our team.

787
00:51:01.600 --> 00:51:03.720
If you just built it clean and simple,

788
00:51:03.720 --> 00:51:06.840
it makes it easier for someone to read it from top to bottom.

789
00:51:06.840 --> 00:51:11.160
But sometimes, between AI or using these low-code tools,

790
00:51:11.160 --> 00:51:14.200
the code that comes out is just basically unreadable.

791
00:51:14.200 --> 00:51:16.800
And so if you're having a hard time reading it,

792
00:51:16.800 --> 00:51:19.080
AI is probably going to have a hard time.

793
00:51:19.080 --> 00:51:20.600
That's the moral of the story.

794
00:51:20.600 --> 00:51:23.880
But very cool.

795
00:51:23.880 --> 00:51:27.560
Yeah, Lucian said, he had a comment there.

796
00:51:27.560 --> 00:51:30.200
I want to give the HM function class.

797
00:51:30.200 --> 00:51:32.600
Yeah, that's good.

798
00:51:32.600 --> 00:51:35.240
Okay, that sounds good.

799
00:51:35.240 --> 00:51:37.320
Well, we'll wrap it there.

800
00:51:37.320 --> 00:51:39.200
If you guys have any questions, drop a comment.

801
00:51:39.200 --> 00:51:40.040
We're happy to chat.

802
00:51:40.040 --> 00:51:43.280
We'll continue next week back to some other

803
00:51:43.280 --> 00:51:45.440
different training and stuff.

804
00:51:45.440 --> 00:51:46.280
But yeah.
