spotifyovercastrssapple-podcasts

Scaffolding Elm Code

We discuss the benefits of automating your Elm boilerplate, and design techniques for APIs that generate code.
March 28, 2023
#79

Transcript

[00:00:00]
Hello Jeroen.
[00:00:02]
Hello Dillon.
[00:00:03]
You know what goes really well with scaffolding?
[00:00:06]
Workers?
[00:00:07]
Builders.
[00:00:08]
Builders, yes.
[00:00:09]
And I think we're going to be talking about both of those things today.
[00:00:14]
Sounds good to me.
[00:00:15]
I feel like you're trying to make a pun but I don't get it.
[00:00:20]
I feel like I have to at least make some sort of attempt at a bad joke to start things off
[00:00:25]
otherwise people will be disappointed.
[00:00:27]
People will be disappointed either way I'm sure.
[00:00:30]
But you know, I have to do my best.
[00:00:32]
Yeah, I mean the joke that I had in mind was let's try to build a good episode or something.
[00:00:38]
Let's try to scaffold a good episode but we'll just go with yours and we will not edit either
[00:00:45]
of these out.
[00:00:46]
Oh no, these bad puns go straight to tape.
[00:00:49]
No second chances.
[00:00:50]
Yeah.
[00:00:51]
I mean we have removed so many good puns in our episodes.
[00:00:57]
People are going to think we only make bad puns.
[00:01:00]
But we just edit those out.
[00:01:02]
There are no good puns.
[00:01:03]
The worse a pun is the better it is.
[00:01:05]
That's the only way you have a true bad pun.
[00:01:07]
A true good pun is a true bad pun.
[00:01:09]
So scaffolding.
[00:01:11]
So we've talked about code generation.
[00:01:15]
We've talked about OMCODEgen which I think is a really lovely tool for scaffolding.
[00:01:21]
So let's first of all, let's get a definition like what is the difference between code generation
[00:01:28]
and scaffolding?
[00:01:29]
So do you want to take a stab at it?
[00:01:32]
Sure.
[00:01:33]
So I would probably say scaffolding at least for computer science, right?
[00:01:39]
Scaffolding is generating code.
[00:01:42]
So it is code generation but it is meant for things that are temporary or to start something.
[00:01:48]
So you generate code that humans are afterwards going to maintain and change to their needs.
[00:01:56]
Whereas if when we talk about more regular code generation like, oh we need to generate
[00:02:01]
code based off this to do things like boilerplate linking, then that is not meant to be touched
[00:02:08]
by a human.
[00:02:10]
So scaffolding is more for, well, let's use this to start with and then we can change
[00:02:15]
it.
[00:02:16]
Right.
[00:02:17]
So I would say that to me, code generation is a superset of scaffolding.
[00:02:22]
Often when we talk about code generation, as you say, we are, especially in the Elm
[00:02:27]
community, we're often referring to generating code that is not user maintained code.
[00:02:33]
You know, GraphQL, like take the GraphQL schema, generate some decoders and encoders or generate
[00:02:39]
an API or Elm SPA generates the wiring for your SPA application or whatever.
[00:02:46]
So those are forms of code generation.
[00:02:49]
But as you said, it's not meant to be touched by a human after it's generated.
[00:02:54]
Whereas scaffolding, and I really like this sort of term and metaphor, you know, you think
[00:02:59]
about the scaffolding around a building, it's like a temporary structure to help you create
[00:03:05]
something that gets removed once that thing has been created.
[00:03:09]
So you know, you scaffold something, you generate some code that a human can then maintain.
[00:03:15]
But once it's sort of built it up for you, you don't care about what was initially templated
[00:03:21]
out for you.
[00:03:22]
Yeah, the one thing that I would say is bad about this metaphor is that usually you end
[00:03:28]
up with a result that is pretty close to the scaffolding.
[00:03:32]
So for instance, if we try to scaffold a, an Elm project, while we generate a main,
[00:03:37]
we generate a init, update, view function, and that structure is still going to be there.
[00:03:44]
You will change the view function, you will change the update function and the init, which
[00:03:49]
is like still most of the application, but the core parts of the structure will still
[00:03:54]
be there.
[00:03:55]
Whereas we'll scaffolding, well, yeah, pretty much everything's going, is going away.
[00:04:01]
Right.
[00:04:02]
It's almost like, often it's like a pre assembled unit that you're probably not going to change
[00:04:07]
the sort of exterior pieces you're going to fit within it.
[00:04:11]
At least in our use cases, that's pretty common.
[00:04:15]
So I think like, so with Elm Pages v3, I've been really trying to, you know, you've talked
[00:04:24]
about this idea a lot that I think you credit Richard Feldman for, of take responsibility
[00:04:29]
for user experiences.
[00:04:31]
I really like this idea of like, looking at what is the user's workflow and their whole
[00:04:37]
experience in building something with your tool or package.
[00:04:42]
And with Elm Pages v3, I've been thinking about like, what is that end to end experience
[00:04:46]
if you're trying to add a new route, if you're trying to wire in a form, right?
[00:04:53]
And you know, I've been thinking about the form API a lot.
[00:04:57]
We did an episode talking about some of those ideas of all these API design techniques you
[00:05:01]
can use to make that easier phantom builder pattern.
[00:05:05]
I have some opinions about ways to reduce the amount of wiring you have to do and leveraging
[00:05:10]
web standards to not have to do extra work.
[00:05:14]
So the framework can manage these things for you and all these things.
[00:05:16]
For those who haven't listened to those episodes, you only have like six or eight episodes to
[00:05:21]
listen to.
[00:05:22]
Go ahead and come back to this episode afterwards.
[00:05:24]
That's right.
[00:05:25]
Pause now and go listen back.
[00:05:27]
So that's one dimension of taking responsibility for user experiences, making that flow simpler.
[00:05:35]
But then how do you create a new form?
[00:05:39]
How do you create a new route with a form?
[00:05:40]
So I've been really thinking about that.
[00:05:42]
And I think scaffolding is the answer.
[00:05:46]
And like Elm SPA, Ryan did a great job kind of creating some templating helpers that you
[00:05:52]
can customize the sort of these these add commands to add new types of pages in Elm
[00:05:58]
SPA.
[00:05:59]
I've been very inspired by Rails and I've gone back and been watching DHH's sort of
[00:06:08]
early days, 17 years ago, demo of building a blog engine in 15 minutes.
[00:06:14]
And he actually really built it in more like three or four minutes if you watch the timestamps.
[00:06:19]
And then he's like adding comment sections and customizing things after that.
[00:06:26]
So that was kind of a groundbreaking idea at the time, I think, in the server world
[00:06:32]
to be able to just like up and running with a server framework rather than like creating
[00:06:37]
a bajillion config files and installing all these dependencies and setting all these things
[00:06:42]
up.
[00:06:43]
You just like create a database, add some fields and run a scaffolding command and then
[00:06:49]
you have an app.
[00:06:51]
And then you customize the views from there.
[00:06:53]
I thought that was really cool.
[00:06:54]
And I think in some ways we've lost touch with that ethos of making it really easy to
[00:07:00]
get up and running with something, but it's still just as relevant today.
[00:07:04]
So I want to make scaffolding a thing again.
[00:07:08]
And I think in the Elm community in particular, because we have to be so explicit with things,
[00:07:13]
scaffolding is a really great opportunity because we like being explicit in Elm and
[00:07:19]
we don't like magic in Elm.
[00:07:21]
And in fact, there's not that much magic you can actually do in Elm.
[00:07:25]
So scaffolding is sort of the best of both worlds.
[00:07:28]
Like you don't have to handwrite all of this boilerplate, but you can sort of get something
[00:07:35]
up and running.
[00:07:36]
Now we still want to reduce the amount of boilerplate you need in the first place, but
[00:07:40]
it can still help you right then.
[00:07:41]
So clarify what you mean with scaffolding in this instance, because I'm familiar with
[00:07:46]
the concept of scaffolding a new project, for instance.
[00:07:50]
The scaffolding something else is a little bit more foreign to me.
[00:07:54]
I mean, I know what you have in mind, but can you maybe explain it?
[00:07:58]
Yeah, absolutely.
[00:08:00]
So for example, I've been, I actually created a video walking through this, but I'm trying
[00:08:06]
to get it down to 15 minutes like that original Rails demo of creating the same sort of full
[00:08:12]
stack blog engine with database persistence in Elm Pages v3.
[00:08:17]
And so do you try to impersonate DHH?
[00:08:21]
No, I don't.
[00:08:24]
Do the same accent, do the same.
[00:08:26]
It's tempting.
[00:08:27]
It is tempting.
[00:08:28]
It's really funny how when he's doing the demo, he like, he runs a command and then
[00:08:34]
like it works and then he goes, whoops, it worked.
[00:08:37]
He always says whoops whenever something works.
[00:08:40]
It's really funny.
[00:08:41]
So I'm definitely tempted to do that too.
[00:08:44]
So like, for example, like creating a new, you know, the route for creating a new blog
[00:08:53]
post entry that has like the slug and title and body.
[00:08:58]
I've created this sort of helper for running like Elm Pages run, which we talked about
[00:09:04]
Elm Pages scripts, refer back to that episode.
[00:09:08]
So you can run these scripts.
[00:09:10]
I created an API for helping you to sort of scaffold things using Elm Code Gen.
[00:09:16]
So you do Elm Pages run, add route, and then you give it the name of, you know, the new
[00:09:24]
blog post page or whatever.
[00:09:26]
And then you can give it a list of form fields, just like a Rails generator.
[00:09:33]
You can give it the like, you can give it title, colon, string.
[00:09:37]
You can do the same type of thing.
[00:09:38]
You can say, you know, you can give like a checkbox field, you can do colon to give the
[00:09:43]
types to these different form fields.
[00:09:45]
But so you can list out these different fields and it generates a route.
[00:09:49]
It has init and update and view and all of these things, which is like, you know, it's
[00:09:55]
a lot to write out a fresh page.
[00:09:58]
And then it generates the form using the Elm Pages form API.
[00:10:03]
And it wires up the rendering of the form and everything.
[00:10:06]
Now, again, I've gone to great lengths to try to make the wiring very minimal for the
[00:10:12]
Elm Pages form API.
[00:10:14]
But I think that that's like, I think we have to attack it from both sides.
[00:10:18]
We have to make the boilerplate minimal, but then we have to help you build that minimal
[00:10:23]
boilerplate to give you the full productivity experience to take responsibility for user
[00:10:29]
experiences.
[00:10:30]
I wanted to be able to have that DHH.
[00:10:32]
Like I want to do that DHH level of productivity.
[00:10:36]
Like I want people and, you know, Rails was sort of a groundbreaking approach to full
[00:10:44]
stack when it was introduced.
[00:10:47]
Now things are moving in this direction where full stack frameworks are often sort of more
[00:10:52]
tied to the front end.
[00:10:53]
So you can render full stack things, pull in database data, and then hydrate that into
[00:10:59]
your preferred front end framework.
[00:11:01]
But we need to like get back to the roots of Rails productivity to make something that
[00:11:08]
people really love and can be very productive in.
[00:11:11]
Now Rails has a lot of magic.
[00:11:14]
Elm has a lot of boilerplate.
[00:11:17]
And between like meta frameworks that take away some boilerplate and scaffolding commands
[00:11:24]
that help you assemble the minimal amount of explicit Elm code to reduce that boilerplate,
[00:11:32]
I think there's something really compelling there.
[00:11:34]
And I think like in Elm, we like writing decoders if we need a decoder.
[00:11:41]
We don't want to be implicit and magical.
[00:11:44]
So we should use scaffolding commands for why not have a scaffolding command for generating
[00:11:49]
JSON decoders, or this is for generating forms.
[00:11:56]
So whenever you say we need to scaffold something, you run a script through Elm pages or something
[00:12:03]
custom that you built or just run Elm code gen with a predefined code generation script.
[00:12:12]
And then you generate a new file.
[00:12:14]
Is that the idea?
[00:12:15]
You generate a new file that represents a route, a new file that contains a decoder
[00:12:21]
and encoder, stuff like that.
[00:12:26]
So one thing that you could also do is just be a regular person.
[00:12:31]
And if there's already a route, just copy paste it and adapt it.
[00:12:37]
Why not do that instead of scaffolding something from scratch?
[00:12:42]
When should you reach out for scaffolding instead of copy pasting, which could be closer
[00:12:47]
to what you want anyway, or also in a way pretty different, but who knows?
[00:12:53]
It's a great question.
[00:12:54]
I think to me, it's about we have the technology, we have the ability to like automate things.
[00:13:02]
And so, but if we don't create nice interfaces and create the right tools to automate these
[00:13:09]
types of tasks, then we are going to just find it easier to copy paste things and we're
[00:13:14]
going to do that.
[00:13:15]
And, you know, that's fine, but exactly like it's just, if we're copy pasting, that's just
[00:13:20]
a sign that we haven't done a good enough job making it easy to do it in a better way.
[00:13:27]
Right.
[00:13:28]
And so what is that better way?
[00:13:29]
What are those tools for that?
[00:13:31]
So like for the, so like in the ElmPages V3 API, I have a couple of scaffold modules,
[00:13:40]
scaffold.form and scaffold.route.
[00:13:43]
And so this is one of the things that I'm experimenting with.
[00:13:46]
I think that Elm CodeGen is a very nice tool for scaffolding out code, but it's somewhat
[00:13:53]
low level.
[00:13:54]
So it generates helpers for you for, if you want to run list.map, you can do gen.list.map
[00:14:00]
and then you can pass in the corresponding expressions or it doesn't generate all of
[00:14:06]
the high level types for you.
[00:14:08]
A lot of the types end up being Elm.expression because it takes some argument, but that argument
[00:14:14]
could be coming from like a variable you have in scope and it, and it helps you sort of
[00:14:19]
manage what variables you have in scope by if you, if you define a let using Elm CodeGen,
[00:14:27]
then it, it lets you name a variable that you have in scope.
[00:14:32]
So you have an actual variable, but it represents an Elm expression, which is the variable in
[00:14:36]
the code you're going to generate.
[00:14:38]
It's a little bit, hurts your brain a little bit, right?
[00:14:40]
But it does a good job sort of mirroring the code it's going to end up looking like, but
[00:14:47]
it only does that for like at a lower level.
[00:14:51]
But if you have like a higher level API, I think there's an opportunity to create abstractions
[00:14:57]
that mirror those APIs.
[00:14:59]
Like if you have a builder pattern, so like in Elm pages v3, there's, there's a sort of
[00:15:05]
a route builder for defining your route.
[00:15:08]
Is it a server rendered route?
[00:15:10]
Is it a pre-rendered route?
[00:15:12]
Does it have local state?
[00:15:13]
Does it have shared state?
[00:15:14]
Does it have no state?
[00:15:16]
So that's a, that's a builder that you can sort of tack on these options.
[00:15:20]
And if you, you know, if you do with no state, then you need to give it a view function.
[00:15:27]
You need to define a view function.
[00:15:29]
If you do build with local state, you're going to, in addition to the view, need an update
[00:15:34]
and it subscriptions message and model, right?
[00:15:38]
So that is too like Elm code gen isn't going to help you with knowing that you need to
[00:15:45]
define an update function in the one case and only a view function in the other case.
[00:15:51]
And you're going to need to define these types.
[00:15:53]
There's no way for it to know that.
[00:15:55]
So we can help it out.
[00:15:56]
Right?
[00:15:57]
So I, I basically mirrored that API and we'll, we'll link to these modules in the, in the
[00:16:04]
V3 beta docs of Elm pages, but I tried to, to give some high level helpers.
[00:16:10]
Now like one of the keys here, you know, when, when you are doing the builder pattern, you
[00:16:16]
have this sort of builder type that at the end you turn into whatever thing you want,
[00:16:23]
like an Elm code gen expression or whatever.
[00:16:25]
Right?
[00:16:26]
So you need a level of safety that you're not just sort of constantly taking an expression
[00:16:32]
and applying functions to that expression and things like that.
[00:16:36]
Right?
[00:16:37]
Because then you just have like this amorphous expression and you can do a bajillion things
[00:16:43]
to it.
[00:16:44]
And it's not really like clear how to scaffold this code.
[00:16:48]
So this API has like a, like a builder for the, for the scaffolding type for scaffolding
[00:16:55]
a route.
[00:16:56]
So it's sort of like a, for the, for the route scaffolding, it's a builder for the route
[00:17:00]
scaffolding.
[00:17:02]
So you apply these sort of sets of options for generating a server rendered route with
[00:17:10]
local state.
[00:17:11]
So now you're tacking on these options to give all of the function definitions that
[00:17:16]
you need for those options in the builder pattern.
[00:17:20]
So I think essentially like my assertion here is that I think it's a good idea for packages
[00:17:28]
to create higher level APIs that mirror their APIs for scaffolding.
[00:17:35]
So like for Elm review, if you're scaffolding out a new Elm review rule, which there is
[00:17:43]
a feature for already, but yeah, right.
[00:17:47]
And we should talk about that.
[00:17:48]
So now I will say when I'm working on Elm review rules, I do often go to the docs and
[00:17:55]
copy paste an example of a visitor, for example.
[00:17:59]
Those examples are just awesome.
[00:18:01]
So go ahead.
[00:18:03]
Yeah.
[00:18:04]
And I mean, and there is definitely an art to having examples that are copy pastable
[00:18:09]
because things are defined in a way that not only compile, but you know, maybe you take
[00:18:16]
in certain things as parameters so that it's like a nice sort of self-contained example
[00:18:22]
that you can probably copy paste into your own code.
[00:18:26]
So there's definitely an art to that.
[00:18:28]
And you've done a good job of that.
[00:18:29]
Now the question is similar to what we were talking about before with like copy pasting
[00:18:34]
a new route module, can we beat the copy paste experience?
[00:18:39]
Because if we can't, then why waste our time?
[00:18:42]
Because we can already copy paste anything and that's what people are going to do unless
[00:18:47]
we, you know, like that sets the bar, unless we go past that, people are just going to
[00:18:52]
copy paste.
[00:18:53]
Yeah.
[00:18:54]
So there's one reason why every time I work on a new rule, I start from scratch.
[00:18:57]
So I do use the Elm review new dash rule command, which scaffolds a new file and it scaffolds
[00:19:05]
a new test file.
[00:19:06]
And reason why it starts from scratch is because I want to do things in a TDD style.
[00:19:12]
And if I copy paste some code, then I don't have the test for them because the examples
[00:19:18]
are good, but there are no tests for that specific example, which makes a lot of sense.
[00:19:24]
I think if I wanted to copy paste something, then I would also have to copy paste a test,
[00:19:29]
which is usually not very applicable.
[00:19:33]
So therefore I start from scratch anyway.
[00:19:35]
That said, there are multiple variants of Elm review rules.
[00:19:39]
So there's module rules, which are very simple or simpler, and there are projects rules,
[00:19:44]
which are a lot more complex.
[00:19:46]
And I do think that I should probably have a scaffold for each of those because every
[00:19:52]
time I work on a new one and I need to use a particular rule, I need to migrate the module
[00:19:58]
rule to a project rule.
[00:20:00]
And that's a lot of work.
[00:20:02]
So yeah, I should probably scaffold a variance of that for the more complex approach.
[00:20:09]
But again, I would still want to start from scratch because of TDD.
[00:20:12]
Interesting.
[00:20:13]
So like, I'm totally with you on the TDD thing.
[00:20:17]
Surprising.
[00:20:18]
I mean, I just brought up TDD because I know you wouldn't be able to contradict me after
[00:20:24]
that.
[00:20:25]
That's right.
[00:20:26]
That's right.
[00:20:27]
Yeah.
[00:20:28]
So here's the way I would think about this is, and this has been my experience, like
[00:20:34]
copy pasting things from Elm review is I'm not copy pasting for the behavior, I'm copy
[00:20:39]
pasting for the wiring and boilerplate.
[00:20:42]
So it's like, I need to add some sort of import visitor.
[00:20:46]
And it's like, now I'm in my workflow, I'm going to have a failing test that says, whatever,
[00:20:53]
this thing that is a contextual thing from the imports, whatever needs to add an import
[00:21:02]
expression or it need if it doesn't already exist, I have a failing test that shows that,
[00:21:07]
okay, now I have a failing test.
[00:21:09]
Now what do I do?
[00:21:10]
I need to add an import visitor.
[00:21:13]
Now I need to copy paste something because I just like the functions have a certain set
[00:21:18]
of types, it gets wired in in a certain place.
[00:21:21]
I'm just going to go copy paste something.
[00:21:23]
I'm going to go find the with import visitor docs and Elm review, and I'm going to copy
[00:21:30]
paste that.
[00:21:31]
And I think that makes sense.
[00:21:32]
I do that as well, quite a lot, especially for the project rules that I mentioned before.
[00:21:40]
So I really like no op type boilerplate for that reason, because you can do it effectively
[00:21:46]
as like an atomic step that's not changing your behavior.
[00:21:50]
So it fits in really nicely with TDD where effectively it's just like with TDD as much
[00:21:56]
as possible, you want to work in atomic steps.
[00:21:59]
So if you have a green test and you want to refactor something, right?
[00:22:05]
Well, if you have an automated refactoring, it just, everything is fixed.
[00:22:09]
If you have a manual refactoring, that's going to at some stage have things in a broken state,
[00:22:16]
even though conceptually it just belongs as one atomic thing.
[00:22:20]
So automation can get us closer to this atomic set of steps.
[00:22:25]
And I think it's the same for like scaffolding, basic wiring.
[00:22:29]
And I think it's, as you say, for that reason, it's best done as scaffolding out no op type
[00:22:33]
things.
[00:22:34]
Yeah.
[00:22:35]
So, so I do absolutely get the no op operations that you mentioned, but for me, scaffolding
[00:22:42]
is usually always either a new file, if we talk about code generation, or if we talk
[00:22:47]
about code snippets in your editor, for instance, then it's pasting or generating a short piece
[00:22:56]
of code.
[00:22:57]
So the, the code snippet could be used to do what you just said.
[00:23:00]
But if you, if you talk about code generation or generate files with code gen or something
[00:23:06]
like that, then you can't just, I don't see how you integrate it into an existing file
[00:23:12]
already.
[00:23:13]
Or at least I don't have the tools for that.
[00:23:15]
Right.
[00:23:16]
It's a great, it's a great point.
[00:23:17]
And I think this is something worth exploring.
[00:23:20]
I think that, you know, maybe, maybe we need some conventions and tools for these types
[00:23:27]
of things.
[00:23:28]
So for example, like I can imagine Jasper has this Elm pair tool, which we should probably
[00:23:36]
dig into at some point, but we'll link to that in the show notes.
[00:23:40]
But it's kind of built on, on the idea of this workflow, similar to these sort of Elm
[00:23:46]
format workflows, where it automatically fixes things to do what it thinks you expect by
[00:23:53]
changing a colon to an equals to make the syntax, right, things like that.
[00:23:57]
It will, you know, fix your import aliases and things like that based on you just editing
[00:24:02]
the code, right?
[00:24:03]
Yeah.
[00:24:04]
And you could also use GitHub copilot or other GPT AI things in the future, which could do
[00:24:11]
the same thing.
[00:24:12]
Sure, sure.
[00:24:13]
As always, like with some amount of trust and distrust of the tool of the general code.
[00:24:20]
Yeah.
[00:24:21]
Right.
[00:24:22]
And you also mentioned a few times on the podcast, and maybe we'll get there at some
[00:24:25]
point having Elm review be able to pretty much act like a language server.
[00:24:32]
Right.
[00:24:33]
Or have some kind of tool that allows you to write custom actions.
[00:24:37]
Right, right.
[00:24:39]
Exactly.
[00:24:40]
And, and now the thing is, like, we already have some, some simpler versions of that.
[00:24:47]
So it's not like a language server that's nicely integrated into editors to expose intentions
[00:24:54]
under your cursor.
[00:24:56]
But you know, my Elm review HTML to Elm package, you can do debug.todo with some HTML with
[00:25:03]
a sort of magic debug.todo call.
[00:25:07]
And it takes that to convert it and to scaffold out some HTML for you.
[00:25:13]
And it sort of intelligent scaffolding because it's aware of context.
[00:25:17]
And so we can use similar patterns.
[00:25:19]
So you could imagine a similar pattern.
[00:25:22]
You know, and Martin Stewart has, like a similar sort of unpublished tool, but he's worked
[00:25:29]
on this Elm review to do it for me.
[00:25:34]
Tool that sort of helps you scaffold out decoders and things like that based on these magic
[00:25:39]
debug.todo calls.
[00:25:41]
Alex Corbin has an Elm review rule for JSON to Elm.
[00:25:46]
Yes, right.
[00:25:48]
Martin Stewart did some things similar to that and others, but yeah, not published.
[00:25:53]
Yeah, I originally got that idea of that pattern from Martin Stewart and used that idea to
[00:26:00]
for Elm review HTML to Elm.
[00:26:01]
And like, so that's a, like, that's kind of a cool pattern.
[00:26:07]
And you could even imagine having, for example, like, to be honest, I haven't integrated a
[00:26:12]
workflow like this myself, but I think it could be cool.
[00:26:16]
What if we have a bunch of these sort of scaffolding Elm review rules?
[00:26:20]
You could even have like a special review scaffolding folder, right?
[00:26:24]
So a normal Elm review folder by convention is in./.review.
[00:26:30]
Well you could have like a separate review config with your scaffolding ones for scaffolding
[00:26:37]
out decoders, HTML, helping you scaffold out Elm review rule helpers, helping you scaffold
[00:26:44]
out Elm pages forms, you know, the sky's the limit.
[00:26:50]
And then have that running in the background in watch mode in auto fix mode.
[00:26:55]
That could be really cool, right?
[00:26:57]
Yeah, or with a nice integration with the editor, which is currently a little bit lacking,
[00:27:03]
but yeah.
[00:27:04]
Right.
[00:27:05]
And I think that this is actually a very nice progression to, you know, sort of do the 8020
[00:27:12]
version of it where you don't have to build a fancy thing that gives you options from
[00:27:18]
under the cursor and you just use debug.todo to have valid syntax, but give a special keyword
[00:27:25]
within the string in the debug.todo that Elm review interprets.
[00:27:31]
I mean, you would probably have a code snippet that creates a debug.todo with the right thing,
[00:27:37]
and then you place part of it and then you would have Elm review.
[00:27:42]
That's an amazing idea too.
[00:27:44]
Yeah.
[00:27:45]
So like, I think it would be really cool to have like, let's say like import visitor,
[00:27:50]
you know, what if, and see, here's the thing is like, like Elm review, the actual Elm review
[00:27:55]
package could even ship some of these either scaffolding helpers for like Elm code gen
[00:28:02]
stuff to help with this or an Elm review rule.
[00:28:05]
Now that's meta if Elm review ships Elm review rules to help you generate Elm review rules.
[00:28:12]
You mean instead of having Elm review rules for reviewing Elm review rules, which is,
[00:28:19]
is probably going to happen at some point, to be honest.
[00:28:22]
The snake eating its tail.
[00:28:23]
Yeah.
[00:28:24]
I love it.
[00:28:25]
I love it.
[00:28:26]
We can add steps to it if you want.
[00:28:30]
Who needs copilot?
[00:28:31]
We're going to have Elm review rules to review scaffolding tools for Elm review.
[00:28:37]
Exactly.
[00:28:38]
That generates Elm review rules to, and then this circle is.
[00:28:44]
I did use Elm review HTML to Elm to build Elm review HTML to Elm.
[00:28:50]
The website version.
[00:28:52]
There's like a site that you can paste the code into and I definitely used it to build
[00:28:56]
itself.
[00:28:57]
So that's good.
[00:28:58]
Gotta love a good bootstrapping story, but, um, and, and I mean, I made Elm review and
[00:29:04]
since then I have not made much with it.
[00:29:08]
No, I do use it at work, but yeah, maybe one day I will start custom projects.
[00:29:17]
Probably an Elm review website.
[00:29:19]
Yeah.
[00:29:20]
Yes.
[00:29:21]
One day.
[00:29:22]
And a scaffolding helper.
[00:29:23]
I think it would be great.
[00:29:24]
Like, so I think I like this pattern.
[00:29:27]
I think, I think I'm a fan of this idea that we've just developed here.
[00:29:32]
You heard it here, folks.
[00:29:35]
And then it never happened.
[00:29:38]
Okay.
[00:29:39]
So you see some value and I mean, I, me too, but you see some value in having scaffolding
[00:29:45]
tools to help you with tasks that you do a lot.
[00:29:49]
Small tasks with things like HTML to Elm or bootstrapping tasks, like a new route or a
[00:29:56]
new rule, that kind of thing.
[00:29:59]
How do you identify what you need or when a scaffolding would be a good tool and where
[00:30:06]
it would be worth the investment mostly?
[00:30:10]
Because I mean, copy pasting is still an option or rewriting everything from scratch is still
[00:30:14]
an option.
[00:30:16]
And for the fair short run, there's always going to be faster.
[00:30:20]
So how do you identify those?
[00:30:23]
And we can talk later about how do we know what to generate?
[00:30:27]
Right.
[00:30:28]
I think it's, I think it's kind of similar to Jeroen's hierarchy of constraints where,
[00:30:35]
so like, if you can make impossible states impossible, then you should do that.
[00:30:41]
Don't write an Elm review rule to give guarantees that the compiler, that you can use the compiler
[00:30:46]
to directly give you that.
[00:30:48]
Like yes, Elm review rules are great, but they're there when you need them because the
[00:30:53]
compiler can't give you that.
[00:30:55]
Right.
[00:30:56]
So it should, you should go up, up the pyramid, start with the most robust way of doing it
[00:31:03]
and the first class approach.
[00:31:05]
So similar with sort of scaffolding, if you can eliminate boilerplate by not needing it
[00:31:12]
at all, because you have a more declarative API, you have a clever trick that reduces
[00:31:19]
the amount of boilerplate you need without introducing magic or complexity, then you
[00:31:22]
should absolutely do that.
[00:31:24]
And again, I went to great lengths to try to do that with my form API design.
[00:31:29]
Right.
[00:31:30]
So attack it from both sides.
[00:31:31]
So that's number one.
[00:31:32]
But then once you do notice that, okay, I've reduced the amount of boilerplate I need to
[00:31:39]
set this up, but it's still, I think that there are a couple of things to consider in
[00:31:43]
your workflow when you notice something taking time, but also getting in the way of your
[00:31:52]
thought process because it, it's a context shift, right?
[00:31:56]
So it's not just the amount of time something takes, but it's the amount of context shifting
[00:31:59]
it requires.
[00:32:01]
And because of that, sometimes these sort of workflow automations can be greater than
[00:32:05]
the sum of their parts where having an automated refactoring, maybe it saves you two seconds,
[00:32:12]
but maybe it makes you more likely to do that refactoring.
[00:32:16]
And maybe it allows you to stay focused on the problem you're solving and let refactoring
[00:32:22]
be something that takes no, no brain space.
[00:32:25]
So that's a win, even if it doesn't save you time.
[00:32:28]
So I think those are a couple of things to consider.
[00:32:32]
There's also just sharing with others in the sense that for instance, you might know how
[00:32:38]
to create a new L module and to wire all the updates functions together, the view functions,
[00:32:45]
the subscriptions and all that.
[00:32:47]
And maybe it takes very little amount of time for you to create all those and to wire everything
[00:32:51]
up.
[00:32:52]
But for a beginner, that will take a lot more time.
[00:32:56]
So if it's for you, it's already automatic and you know how you could do, and you know
[00:33:03]
how you could automate that, then that could be worthwhile for a beginner.
[00:33:07]
Right.
[00:33:08]
Or maybe not this example, but yeah.
[00:33:10]
Yeah.
[00:33:11]
You can use it to model best practices.
[00:33:14]
You know, the things that get copy pasted might not end up being the best examples of
[00:33:19]
things to get copy pasted.
[00:33:20]
So you can sort of model the ideal way to write something in sort of scaffolding helpers.
[00:33:29]
That's actually something that I've found that, that's actually something that I'm finding
[00:33:34]
to be a lot more of a problem than I expected is that if you leave bad code around, it gets
[00:33:40]
copy pasted a lot.
[00:33:42]
Exactly.
[00:33:43]
It's always the bad code that gets copy pasted, but that might be some bias.
[00:33:49]
I hope it's a bias.
[00:33:50]
No, it is exactly.
[00:33:53]
And which is something to say about code debts, like fix it now or it will multiply.
[00:34:00]
Exactly.
[00:34:01]
Exactly.
[00:34:02]
Yeah.
[00:34:03]
Sandy Metz talks about this a lot in refactoring.
[00:34:06]
She has some really great books on refactoring in Ruby, but she talks about a lot of just
[00:34:11]
sort of general best practices and refactoring techniques.
[00:34:14]
And she talks about sort of, I can't remember the word she used, but something like replicability
[00:34:21]
or like somehow code wants to be duplicated.
[00:34:26]
So there's a cost to having code that doesn't represent the way you want to do something
[00:34:33]
in your code base.
[00:34:34]
That said, I mean, you can write tools to say, well, this is the way things should be.
[00:34:41]
But if you're starting with a new approach and you're still exploring and like, well,
[00:34:47]
is this the right approach?
[00:34:48]
Maybe we'll try it out and come back to it later.
[00:34:52]
If you don't know what the right approach is yet, then you can't really make tools for
[00:34:58]
it.
[00:34:59]
So, but for things that you do over and over again and always in the same manner, yeah,
[00:35:06]
make tools, make your life easier.
[00:35:09]
Right.
[00:35:10]
Now, just as you want to keep in mind, like what direction you want to guide the code
[00:35:18]
with your scaffolding and your automation tools and how that shapes the code, you also
[00:35:23]
want to make sure that you don't make it too easy to generate things that you don't necessarily
[00:35:30]
want or to duplicate things rather than reusing shared things.
[00:35:35]
This is another consideration.
[00:35:37]
Yeah.
[00:35:38]
Are you thinking of, for instance, when someone creates a module and they add in it, update
[00:35:42]
view and in the end they only need the view?
[00:35:45]
Is that kind of thing?
[00:35:46]
Yeah, that would be one example.
[00:35:48]
Or maybe it's so easy to scaffold out a new decoder that you don't go to see if there's
[00:35:56]
an opportunity to reuse something that already exists somewhere else because it's so easy
[00:36:01]
to just build up the decoder using these automation helpers you have.
[00:36:05]
But yeah, I think, you know, with Elm, we like being explicit.
[00:36:10]
We like to have all of the information of how to do something in code, not defined through
[00:36:17]
magic, not implied through some type somewhere.
[00:36:21]
And so I think scaffolding is like a really good technique to bridge that gap.
[00:36:27]
So like one of the things to think about also is like, what are the inputs to your scaffolding?
[00:36:32]
So like, you know, we talked about using these sort of debug.todo comments that have some
[00:36:38]
sort of something in the debug.todo string that tells it what to do, what to replace
[00:36:45]
that with.
[00:36:46]
That's one pattern.
[00:36:47]
Having sort of an inline thing in the code telling you that you want to do something
[00:36:53]
with that.
[00:36:54]
You can use a CLI to scaffold out new things.
[00:36:58]
You can pull in data from different sources.
[00:37:02]
You can pull in, I mean, I think it would be really cool to have a JSON decoder scaffolding
[00:37:10]
helpers that take a URL or an HTTP request or something and scaffold that for you.
[00:37:17]
So I think it's worth thinking about what are the inputs to and how can we really automate
[00:37:23]
the process to make it really seamless to not have to think about boilerplate in our
[00:37:28]
own code.
[00:37:29]
Yeah.
[00:37:30]
At work we have a few code generation tools or scaffolding tools, for instance, to create
[00:37:37]
routes and then we have a separate code generation script to combine them in an Elm SBA like
[00:37:45]
way.
[00:37:46]
So there's a lot of scaffolding and code generation going around that.
[00:37:52]
One problem is like, usually people don't know that these things, these scaffolding
[00:37:57]
tools exist.
[00:37:58]
So they're in the readme, but no one reads the readme because I mean, it says readme.
[00:38:04]
It doesn't say ignore me.
[00:38:06]
Interesting.
[00:38:07]
That could be fun file to have ignore me.mt.
[00:38:12]
People might actually read that one.
[00:38:14]
I wouldn't read it.
[00:38:15]
I like it.
[00:38:18]
So yeah, we have the problem, but I mean, the tool is there sometimes.
[00:38:26]
It's just not going to be used.
[00:38:28]
That's all.
[00:38:29]
So if you do have like, if you make a package with those scaffolding tools integrated into
[00:38:36]
the package, then I would really recommend like add a nice section in your readme about
[00:38:40]
like, Hey, you should use these things.
[00:38:43]
Then there's the same question I was wondering about a few years ago is like, well, if you
[00:38:47]
have a package, like let's say Elm UI, should you have Elm review rules that come with it?
[00:38:54]
And I would, today I would probably say no, because then you're adding additional dependencies
[00:39:01]
and you should probably have a separate package with the Elm review rules.
[00:39:05]
And I think I'm thinking maybe you should have that too for the scaffolding.
[00:39:09]
I mean, I think the challenge there is keeping them in sync between versions, because if
[00:39:16]
it's in the same package, so like if you have a breaking change, how do you, how do you
[00:39:21]
make sure that the scaffolding tools are being run against the same target version?
[00:39:27]
That's one challenge that you introduce by having them be separate.
[00:39:31]
Yeah.
[00:39:32]
But now, I mean, the problem with dependencies that you now depend on Elm Code Gen, which
[00:39:37]
has maybe other dependencies, and now you risk of having like some major dependency
[00:39:45]
version mismatches, which I always find very scary, at least.
[00:39:50]
Right.
[00:39:51]
So just to elaborate, for people who might not know, in Elm, pulling in dependencies
[00:39:59]
to a package doesn't eagerly pull in those dependencies to your actual code.
[00:40:05]
So it's not like JavaScript that it is going to bloat your bundle size just because you
[00:40:10]
depend on an extra dependency, or that it's going to install it for every single time
[00:40:16]
you npm install your node modules is going to have a duplicate version of that code.
[00:40:20]
And it's going to blow up your file size on your system.
[00:40:23]
There's a single shared place that it caches on your system.
[00:40:27]
So it doesn't really cause problems for that.
[00:40:30]
Elm has live code inclusion, or dead code elimination.
[00:40:34]
So it doesn't really cause issues for that if you don't call a function in your production
[00:40:38]
code that uses the scaffolding thing, it doesn't pull in those dependencies.
[00:40:42]
But if you're upgrading to a new version of some package, and that dependency creates
[00:40:48]
a conflict between that upgrade, that's where it causes headaches.
[00:40:52]
Yeah, it's mostly those Elm Community extra packages that scare me a lot.
[00:40:59]
Which often it's nice to just like inline those because it's not worth making it difficult
[00:41:04]
for people to...
[00:41:05]
Yeah.
[00:41:06]
So again, to clarify, if there's a new major version of, let's say Elm Community list extra,
[00:41:15]
so there's v9, and then an old package or another package depends on v8, then you can't
[00:41:20]
install those two at the same time, because of how Elm works, which makes things simpler.
[00:41:26]
But these kinds of problems do arise.
[00:41:30]
Yeah, we need some sort of like scaffolding tool to inline extra helper functions.
[00:41:37]
No, I mean, it's, it would be nice.
[00:41:41]
It's definitely not ideal to like copy paste these helpers into packages to reduce these
[00:41:47]
dependencies.
[00:41:48]
But if it's like one function from list extra or two functions from list extra, it's not
[00:41:52]
worth having users have that dependency dance if something has a breaking change.
[00:41:58]
I mean, from what I understand, NPM has this ability to install multiple versions of a
[00:42:06]
package, right?
[00:42:07]
Right.
[00:42:08]
But that's also the reason why your node modules are so huge, because it installs plenty of
[00:42:16]
those versions, because you can depend on packages so easily.
[00:42:21]
Right.
[00:42:22]
And it can cause weird unexpected behavior too, right?
[00:42:25]
So it's like, it definitely simplifies like reasoning about your code to be like, this
[00:42:30]
is the version of this dependency that that all of my code uses.
[00:42:35]
Yeah.
[00:42:36]
So yeah, Elm has this little limit limitation, but yeah, we're looking at the node modules.
[00:42:43]
I'm like, yeah, this is pretty good.
[00:42:44]
Actually.
[00:42:45]
It's a pretty sane limitation.
[00:42:46]
Yeah.
[00:42:47]
It's a sane constraint.
[00:42:48]
Elm is good at this.
[00:42:50]
You mentioned inputs for the scaffolding, but you were talking about how do you integrate
[00:42:56]
these scaffoldings?
[00:42:57]
How do you use them?
[00:42:58]
What method?
[00:43:00]
What about the inputs to the scaffolding tool?
[00:43:03]
Like should you, for instance, should you have options to your scaffolding scripts?
[00:43:11]
Let's say we want to make a new module or let's make a new Elm project.
[00:43:17]
Should we have an option to say, well, I want a browser sandbox or a browser elements or
[00:43:24]
a browser application and so on and so on.
[00:43:27]
How custom do you think these should be?
[00:43:29]
Right.
[00:43:30]
I think first of all, it has to beat copy pasting as a user experience.
[00:43:37]
So that's one way to beat copy pasting as a user experience.
[00:43:40]
Now if you make the running the scaffolding tool overly complex, it's not going to beat
[00:43:46]
copy paste, but fair.
[00:43:48]
If you can have a nice CLI.
[00:43:50]
Now Elm pages scripts have the option to do a CLI options parsing that's in pure Elm using
[00:43:58]
my Elm CLI options parser package.
[00:44:01]
So you can use that to add configuration to a scaffolding script.
[00:44:07]
So I think that's like a pretty nice thing to do.
[00:44:09]
If there's like one little flag you want to add to configure one, one change, you should
[00:44:14]
do that.
[00:44:15]
Do you think it's nice for a scaffolding tool to have a few prompt questions or should everything
[00:44:21]
be configurable through the CLI flags?
[00:44:24]
I mean, you could do both.
[00:44:26]
Like if you provide something with the CLI flag that you don't have to ask the question,
[00:44:31]
but they're not necessarily as discoverable or have the same amount of explanation in
[00:44:38]
the prompt.
[00:44:39]
Right.
[00:44:40]
I quite like prompts, but it does make things a bit slower.
[00:44:43]
Right.
[00:44:44]
Yeah.
[00:44:45]
It's definitely a trade off between ease of discovery versus ease of use once you've gotten
[00:44:50]
comfortable with it.
[00:44:52]
So I mean, sometimes tools will sort of have a required flag, but if you don't pass in
[00:45:00]
that flag to the CLI, it will prompt you for it.
[00:45:03]
That can be a nice way to do it.
[00:45:05]
Sort of a best of both worlds approach.
[00:45:07]
It strikes me too that like, so with these magic debug.todo comments that an Elm review
[00:45:13]
rule can find with the special string in there, you could, you know, I think it's good to
[00:45:21]
have conventions for these types of things.
[00:45:23]
So they're discoverable.
[00:45:24]
You could even imagine having like, I don't know, let's say that all of your magic debug.todo
[00:45:31]
comments start with triple exclamation point.
[00:45:34]
So you have three exclamation marks and then maybe the Elm review rule watcher that's running
[00:45:42]
in the background says like, instead of giving a fix, if you just have three exclamation
[00:45:48]
points without anything after it, maybe it says, Hey, here are the ways to fix that.
[00:45:54]
Here are the options you can pass me.
[00:45:57]
So you could have a discoverability experience through that.
[00:46:01]
Right.
[00:46:02]
So like, I think there's a UX opportunity here.
[00:46:06]
It could even be an interesting thing to have like a shared package to crystallize some
[00:46:12]
of these conventions, because I think like conventions are important for user experience
[00:46:16]
because otherwise like people aren't going to go to the readme to look it up.
[00:46:21]
You have to like make it more within reach.
[00:46:24]
We just have to understand that about people that they're probably not going to read the
[00:46:28]
readme, but if we make it easy for them to guide them in the right direction, when they
[00:46:33]
try to do something, they might actually use it instead of copy paste.
[00:46:37]
That's actually something that is, that's actually something that I find it to be a
[00:46:40]
bit of a shame that it's not very discoverable.
[00:46:43]
So for instance, if we're pairing together and I'm running a function or actually you
[00:46:48]
just look at my code, because I've sent you a pull request and you see a function that
[00:46:54]
I've used and you've never seen before, or you go to the documentation and you see, Oh,
[00:46:59]
well, list.partition is a thing.
[00:47:01]
Oh, that could be pretty useful.
[00:47:03]
I will use that next time.
[00:47:05]
But you can see that because it's in the code and it's committed and all that.
[00:47:09]
But all the things that I have done that you have not seen because it's not committed,
[00:47:14]
like all the keyboard shortcuts that I use, all the editor integration that I use, all
[00:47:18]
the scaffolding tools that I use, you don't see them.
[00:47:23]
That's actually like one of the reason why people say, Oh, you should pair together because
[00:47:27]
that's when you learn so many new things.
[00:47:30]
Every time I pair, I learn a new thing with someone.
[00:47:33]
A hundred percent.
[00:47:34]
Or teach someone something new.
[00:47:36]
It goes both ways.
[00:47:37]
Totally.
[00:47:38]
I agree.
[00:47:39]
And workflow, like, I mean, one thing I really learned from a lot of sort of people in these
[00:47:47]
software craftsmanship circles is like, workflow and automation are not just like a vanity
[00:47:56]
sort of cool way to customize your system.
[00:48:01]
It's not like, Whoa, look at this cool theme I have and look at this cool shortcut I have
[00:48:05]
for this and this cool automation.
[00:48:07]
It's like, no, actually, like automating things is a really important part of like building
[00:48:14]
great software.
[00:48:15]
In my view of building great software, like this is a key way to get better at doing that.
[00:48:22]
So I think it's be taken seriously.
[00:48:24]
Yeah.
[00:48:25]
I mean, it would be hard to argue that using notepad is the way to write applications today
[00:48:34]
when the only shortcuts you have is control C and control V.
[00:48:37]
Right.
[00:48:38]
So yeah, you know, all the things that a editor gives you, even a simple one, well, they're
[00:48:43]
useful.
[00:48:44]
They're really useful.
[00:48:45]
Yeah.
[00:48:46]
And again, because it helps you get to those atomic steps of changing things.
[00:48:51]
Now, I'm not going to say that somebody can't create great software without these things.
[00:48:56]
It's just like they're missing out on a superpower.
[00:49:01]
You can also like another superpower is being really good at modeling systems and knowing
[00:49:10]
when to say no to certain features and writing tests first and things that you can do without
[00:49:16]
automating these steps.
[00:49:17]
So I'm not saying that that's the only part of building great software, but I think it's
[00:49:24]
like to me, it's an important piece of the puzzle.
[00:49:26]
It's an important tool in the toolkit.
[00:49:28]
So going back to scaffolding and all those things, what would you write in the scaffolding
[00:49:34]
code?
[00:49:35]
So again, let's take the example of you scaffold a new application with a main and init update
[00:49:43]
view browser data application, whatever.
[00:49:47]
How much comments code would you integrate?
[00:49:51]
So for instance, one thing that I might be wondering is like, well, if I want this code
[00:49:56]
to be for anyone who's new to Elm, then I might add a few comments that says, well,
[00:50:03]
oh, this is main, this is how your application starts and this is how it works.
[00:50:07]
And then you have a comment around init that says, well, this is how we initialize your
[00:50:12]
application and one for model.
[00:50:14]
This is all the data that your application can hold, et cetera, et cetera.
[00:50:19]
So is that something that you think we should do?
[00:50:23]
And also like maybe also steps for, oh, well we have now scaffolded this thing and this
[00:50:28]
is where you should change your code.
[00:50:30]
Like here's where you should add a new kind of message variants or this is where you shouldn't
[00:50:36]
handle this new updates, this new message.
[00:50:40]
How much should you help someone?
[00:50:43]
And I'm guessing it's like, if it's for you, you don't care because you know what you need
[00:50:47]
to do.
[00:50:48]
I mean, you've been able to automate this, right?
[00:50:50]
But I'm guessing if you're in a team and you often have new developers joining your team,
[00:50:55]
then maybe it's worth adding all these comments, but then you probably also want to strip them
[00:51:00]
out.
[00:51:01]
Yeah.
[00:51:02]
I'm a little bit torn.
[00:51:03]
Yeah.
[00:51:04]
So back to this sort of idea that Sandy Metz has that code tends to be duplicated or replicated.
[00:51:11]
I think the term she uses is, is that good code is exemplary, exemplary, exemplary, exemplary,
[00:51:20]
exemplary.
[00:51:21]
We'll see how our transcripts do on that.
[00:51:25]
Maybe it'll just strip it down to one word.
[00:51:28]
We'll see.
[00:51:29]
Yeah, I think it's you, you want, like, if you don't want to have comments in your code
[00:51:36]
explaining this goes here, this is where you add things.
[00:51:40]
I personally would tend to avoid including that in the scaffolding as well.
[00:51:46]
I would, I would want to add that more as like output from running the scaffolding command
[00:51:51]
and it says, great, I added this thing.
[00:51:54]
Here are your next steps.
[00:51:56]
Now what I would want to do.
[00:51:57]
So for example, let's say we're scaffolding out in a new route module for SBA, Elm pages,
[00:52:04]
your custom homegrown SBA helper, whatever.
[00:52:07]
So personally, I tend, I actually tend to find it more useful to like, have an init
[00:52:16]
function defined, even if you don't use it initially.
[00:52:20]
I just find that easier.
[00:52:21]
So then you don't need a comment to say like, comment, if you want to add init and messages,
[00:52:28]
you can change these things.
[00:52:29]
Just, just have, you know, type message equals no op or whatever, you know, but I was, I
[00:52:39]
was thinking of a comment next to the message type, but always including the type, the message
[00:52:45]
type.
[00:52:46]
Right, right, right.
[00:52:47]
Commenting it out is also a possibility.
[00:52:49]
Yeah.
[00:52:50]
Yeah.
[00:52:51]
And, and so like, basically I would tend to, instead of having comments, maybe have a little
[00:52:59]
bit of terminal output to guide people as, as far as that's helpful, maybe even link
[00:53:04]
them to a guide.
[00:53:05]
If somebody's new to a thing, if you're new to our, the way that our route modules work,
[00:53:10]
here's some documentation about it.
[00:53:12]
And now somebody, somebody is not going to be new to a project, read the entire read
[00:53:18]
me and everything about it, but maybe when they're new to a project, they run the scaffolding
[00:53:23]
command and they see output that links them to the relevant thing with like a minimal
[00:53:29]
output.
[00:53:30]
Maybe then they'll click it and read it because it's relevant to them now.
[00:53:32]
So showing people contextually relevant information, I think is a good technique.
[00:53:36]
And also like showing exemplary code that makes it easy to change in the way you want
[00:53:43]
it to evolve.
[00:53:44]
So like if you have a, if you have a message type that is unit type, type message equals
[00:53:51]
unit, it doesn't make it easy to evolve that module in an idiomatic way.
[00:53:55]
So it's better to have custom type there.
[00:53:58]
And it's better to have your update function do a case expression on the message because
[00:54:03]
that's what's idiomatic or whatever the idiomatic pattern is for your code base.
[00:54:07]
So I would say like, try to set up the idioms in a way that's easy to evolve from as a starting
[00:54:13]
point in your scaffolded code.
[00:54:15]
Even if that's like a little verbose sometimes, I, I think it's worth it.
[00:54:20]
And if things are not clear, then it's also potentially API design that needs to come
[00:54:25]
into play.
[00:54:26]
Like you're not going to be able to change the Elm browser API, but if it's your scaffolding
[00:54:31]
in your routes and your route is something that you control, then maybe you can change
[00:54:36]
the names of the fields of the functions to make it very explicit.
[00:54:40]
Like, Hey, this is probably what you need to do in order to do what you want to do.
[00:54:44]
So make good APIs and things will happen automatically.
[00:54:48]
Yeah, totally.
[00:54:50]
Totally.
[00:54:51]
Yeah.
[00:54:52]
So for your Elm review scaffolding, what does, what does it give you?
[00:54:58]
So you've got scaffolding for an Elm review package and you've got scaffolding for an
[00:55:04]
Elm review rule, right?
[00:55:06]
Yep.
[00:55:07]
And what do those give you?
[00:55:08]
So the package creates a whole new package.
[00:55:11]
So it creates an Elm JSON file.
[00:55:14]
It creates a readme that is formatted in a way that looks pretty much like my other packages,
[00:55:22]
which is the way that I recommend things.
[00:55:26]
It comes with the GitHub action scripts.
[00:55:28]
So if you just push this to GitHub, then you will have a CI.
[00:55:35]
And you also always have to create at least one rule.
[00:55:37]
And then for that one rule, it creates a module for the rule and a test module for that rule.
[00:55:43]
And if you run Elm review new rule, then you also get a new rule and a new test file.
[00:55:49]
And every time you add a new rule, it will automatically update the readme to list that
[00:55:56]
rule and it will add it to the exposed modules in your Elm JSON file.
[00:56:01]
And there's also one file that I generate, which is some documentation of how you should
[00:56:08]
manage your project.
[00:56:09]
Like how do you publish this package for the first time and afterwards, because the first
[00:56:15]
time you have to do it manually, the second time we're using your script to automatically
[00:56:20]
publish something every time you change the version in your Elm JSON file.
[00:56:25]
Oh, and also a new package comes with a review configuration.
[00:56:31]
Right.
[00:56:32]
Yes, very meta.
[00:56:33]
And yeah, this is one thing that I quite like about it is there's an Elm review rule that
[00:56:38]
reports comments when they contain some words and it contain, it will flag everything that
[00:56:44]
contains replace me.
[00:56:46]
And I put that replace me in a lot of places.
[00:56:49]
So for instance, every time you create a new rule, that rule will have already some documentation.
[00:56:55]
It will say this rule reports dot dot dot replace me.
[00:57:00]
And it says this rule for instance, will flag some code and it will have a replace me there
[00:57:06]
and it will not flag this code and it will have replaced me.
[00:57:10]
So I'm forcing the author to at least remove that code or that there was documentation
[00:57:18]
better to replace it.
[00:57:21]
So I'm forcing them to think about documentation in a way they don't have to do it now, but
[00:57:26]
they will have to do it in order for this CI to pass.
[00:57:30]
Right.
[00:57:31]
Yeah, I think you've hit on another dimension of scaffolding that I think is really helpful
[00:57:38]
is like, sometimes you don't like sometimes you need to have a placeholder where you say
[00:57:43]
like, you need to do some like replace this thing and you just you can't fill it in for
[00:57:49]
them but you can at least make it very obvious that something needs to be done there.
[00:57:54]
Yeah.
[00:57:55]
I can fill in the rule name because I know it because I'm generating the prompt for it.
[00:58:02]
But the documentation I will not be able to do that.
[00:58:04]
Right.
[00:58:05]
I don't want them to think about it.
[00:58:07]
You can wire in a GPT API call and take the package name and then generate it.
[00:58:15]
Maybe maybe.
[00:58:16]
Next release.
[00:58:17]
Yeah.
[00:58:18]
I've also I used that same pattern of the replace me and I think I used your same setup
[00:58:27]
from your Elm review in it set up there for the Elm package starter, which is a little
[00:58:34]
template repo, which again, that's another another approach to scaffolding is having,
[00:58:39]
you know, a GitHub template repo.
[00:58:42]
I just recently used the Elm package starter and it was really nice.
[00:58:47]
And I used the Elm review rule to tell me all the replace me spots and then went through
[00:58:52]
and filled those out.
[00:58:53]
And it's a nice workflow.
[00:58:55]
Oh, I'm surprised.
[00:58:56]
Past Dillon did did a good job at it.
[00:58:59]
Yeah, I know.
[00:59:00]
I was pleasantly surprised too.
[00:59:05]
And so the now another cool technique you mentioned there was like replacing sections
[00:59:11]
of the read or, you know, modifying the readme when you add a new rule.
[00:59:16]
That's pretty cool.
[00:59:17]
So I think now it's also possible to like modify code.
[00:59:22]
Of course, this becomes much more complicated than like adding a new scaffolded file to
[00:59:27]
like do like an incision, you know, surgery there.
[00:59:32]
But but it's possible.
[00:59:35]
And I think one thing that helps a lot with that is conventions.
[00:59:38]
If you have clear conventions, and you can just sort of follow like, okay, if these exact
[00:59:44]
conventions are followed, and I can check that it's safe to to modify this thing, because
[00:59:51]
I know these exact conventions will have these exact things I can easily check for.
[00:59:56]
Otherwise, I'm going to bail.
[00:59:57]
But if you follow these conventions, then I will allow you to modify it.
[01:00:01]
So that's sort of a cool, like, not like scaffolding within an existing file technique, I think.
[01:00:09]
Yeah.
[01:00:10]
As you say, like, it's incision, so you I need to detect like, well, where's the section
[01:00:15]
where list all the rules, and I'm expecting it to have some kind of shape or try to do
[01:00:21]
some pattern matching.
[01:00:22]
And so far, no one has complained about it.
[01:00:26]
But it works as long as people don't touch it in a weird way.
[01:00:30]
But I don't know if they know it's a feature.
[01:00:33]
Well, actually, a lot of people don't use my package scaffolding tool, because they
[01:00:40]
don't know it takes because they don't know it is.
[01:00:43]
I used it for creating new packages, and I like it.
[01:00:48]
Yeah, yeah.
[01:00:51]
But I think like, the fact that this sort of technique of modifying things easily without
[01:00:58]
too much fancy static analysis and control flow analysis and type inference and stuff,
[01:01:05]
I think the fact that that depends on using some very clear conventions can be a feature
[01:01:12]
not a bug.
[01:01:13]
Because like enforcing certain conventions and giving you these nice automations you
[01:01:19]
can use if you follow these conventions can strengthen the cohesiveness of a code base.
[01:01:26]
In this case, I'm touching the readme, but if I was touching Elm code, then we would
[01:01:29]
have the compiler to help us out.
[01:01:31]
If we don't have that, or if the Elm compiler doesn't help in this case, then yeah, using
[01:01:37]
conventions is a good way around that.
[01:01:41]
Another thing I played around with a little bit in these scaffolding helpers for Elm pages
[01:01:45]
is I noticed, again, like inspired by this DHH demo, I was trying to notice all the things
[01:01:54]
that were slowing me down when I was using the scaffolding.
[01:01:57]
So one thing I noticed was like originally for the add route scaffolding command I had,
[01:02:03]
I noticed that I would go in, I do add route with a few form fields, it generates a route
[01:02:09]
with with a form wired in.
[01:02:11]
And that's great.
[01:02:12]
But then in the Elm pages sort of full stack code, where it's receiving that form submission,
[01:02:21]
and it has the parsed form, I was debug logging it.
[01:02:26]
And what I found when I was trying to make the demo very short, was that I would forget
[01:02:32]
to take out the debug.log sometimes, and then I would do the part of the demo where I ship
[01:02:38]
it to Netlify and show the full stack thing working.
[01:02:41]
And then it would have an error because the build command was failing because it had a
[01:02:45]
debug in it.
[01:02:46]
So that's sort of like not setting it up for success.
[01:02:49]
And again, not being exemplary code that is making it easy to evolve in the shape you
[01:02:55]
want it to evolve in.
[01:02:57]
So I modified it to take this form that it's generating.
[01:03:01]
So you give the CLI these form fields.
[01:03:05]
These form fields have types.
[01:03:07]
The checkbox has a boolean type, a text field has a string type.
[01:03:11]
So it knows sort of the types.
[01:03:13]
It generates a record for the parsed form that you can change the scaffolding to map
[01:03:20]
it into nicer opaque types or whatever you want to do.
[01:03:24]
But it gives you a sort of good baseline of strings and bools and date types for the parsed
[01:03:30]
form.
[01:03:32]
And then I have a scaffolding helper.
[01:03:35]
So you can take that type in addition to using it to just generate the type alias for the
[01:03:42]
parsed form.
[01:03:44]
It can generate a JSON encoder.
[01:03:47]
And so instead of doing debug.log, I took that parsed form type.
[01:03:53]
I know what the type is in the generated code, and I generate a JSON encoder for that.
[01:04:00]
And I send it out through a log, which is not a debug log, but it's an actual back-end
[01:04:06]
task log that you can ship in a production code base.
[01:04:10]
So now, and this is all user configurable.
[01:04:12]
So if your code base evolves and you want to use a different pattern, you don't want
[01:04:17]
to JSON encode it, you don't want to log it, you want to do some specific thing to it,
[01:04:21]
you can follow those patterns and change it because this scaffolding API I built allows
[01:04:26]
you to customize that.
[01:04:28]
But it gives you the building blocks to generate these things.
[01:04:31]
And what I found was when I was trying to basically like speed run this demo, I was
[01:04:38]
more set up for success because actually it was like, oh, actually, I do want to use a
[01:04:42]
JSON encoder.
[01:04:43]
But instead of sending the JSON encoder, and then encoding that to a string, and then logging
[01:04:48]
that, I want to send it through a custom back-end task or whatever.
[01:04:52]
So I was trying to sort of like use these same idioms in a way that would be like meaningful
[01:05:02]
and help me guide me in the direction my production code wants to go.
[01:05:05]
I'm happy with it.
[01:05:06]
I think it's also a nice pattern to like use types and create Elm CodeGen helpers to work
[01:05:12]
with types like creating an Elm CodeGen helper to JSON encode a type.
[01:05:17]
It is something that we can build.
[01:05:20]
So there's some really cool possibilities.
[01:05:22]
Like I think building higher level helpers to help generate things with Elm CodeGen is
[01:05:27]
like a really exciting space.
[01:05:30]
What should we tear this scaffolding down?
[01:05:32]
We should.
[01:05:33]
I did mention it before with GPT and all those AI tools.
[01:05:40]
Maybe this whole conversation will end up being pretty useless.
[01:05:46]
I don't know.
[01:05:47]
We'll see.
[01:05:48]
I mean, we certainly can guide people to do the right thing better than what we can teach
[01:05:55]
such a tool to do, especially if we can't teach it's anything, as far as I know.
[01:06:01]
But I mean, we'll see how those will evolve.
[01:06:05]
It's a fascinating topic.
[01:06:07]
My instincts on this.
[01:06:09]
Now this may be, you know, me becoming an old curmudgeon or something.
[01:06:13]
I don't know.
[01:06:14]
But my instinct is that there's value to explicitness.
[01:06:19]
There are worse things than magic.
[01:06:21]
Yeah, there are worse things than magic.
[01:06:24]
Now I think like having explicit tools for scaffolding code still has value even with
[01:06:31]
AI assist tools.
[01:06:33]
I'm not saying that AI assist tools aren't also helpful, but if you can create high level
[01:06:39]
helpers to help you do a very specific thing in a very exact way, you don't have to think
[01:06:46]
about did this actually give me what I want?
[01:06:48]
Is it idiomatic?
[01:06:50]
You don't have to second guess it.
[01:06:51]
You don't have to double check it.
[01:06:52]
You just use it like a high level thing.
[01:06:54]
There's no context shifting.
[01:06:55]
You think of it as a high level atomic thing.
[01:06:57]
I'm adding a route with a form.
[01:06:59]
Boom.
[01:07:00]
So to me, it still serves a purpose.
[01:07:03]
And then I think that there could be interesting opportunities for an interplay between these
[01:07:07]
sort of scaffolding commands and AI to sort of work together.
[01:07:12]
And I think that's another interesting space to explore.
[01:07:14]
Yeah, absolutely.
[01:07:16]
I for one welcome our new AI overlords.
[01:07:20]
I honestly prefer my Elm Review overlords because I know what they can and what they
[01:07:28]
can't do.
[01:07:30]
And I know that they can't do much about how I live.
[01:07:36]
And that's a good thing.
[01:07:39]
I think that like pure functions and static typing, I imagine a world where that is a
[01:07:45]
superpower for AI assists.
[01:07:48]
I don't think we're at that world yet, but I think that world could come to pass.
[01:07:53]
We'll have to see.
[01:07:54]
Same here.
[01:07:55]
But that might be a topic for another conversation.
[01:07:58]
So Jeroen, until next time.
[01:08:02]
Until next time.