elm radio
Tune in to the tools and techniques in the Elm ecosystem.
Avoiding Unused Code
We discuss how to avoid unused Elm code, why it matters, and what leads to unused code in the first place.
Published
August 14, 2023
Episode
#88
elm-review-unused
Safe dead code removal in a pure functional language
Elm Town 60 with Wolfgang Schuster - Productivity and the culture of moving a little bit slower
Transcript
[00:00:00]
Hello Jeroen.
[00:00:02]
Hello Dillon.
[00:00:04]
Do you ever feel used, used and abused?
[00:00:06]
Or are you the kind of person who
[00:00:08]
likes to feel appreciated
[00:00:10]
and you like it when people take
[00:00:12]
advantage of your skills?
[00:00:14]
I really do.
[00:00:16]
I especially like it when they
[00:00:18]
use me, not abuse me
[00:00:20]
and they pay me.
[00:00:22]
That's even better.
[00:00:24]
That's even better, but...
[00:00:26]
Maybe you're a little bit like Code then, Jeroen,
[00:00:28]
because you don't like being unused.
[00:00:30]
I don't, no.
[00:00:32]
No, I don't.
[00:00:34]
It's a pretty good feeling when
[00:00:36]
your work is appreciated
[00:00:38]
and... Oh, okay.
[00:00:40]
Oh, this was a pun
[00:00:42]
to introduce a topic
[00:00:44]
of unused things.
[00:00:46]
It was all a ruse. I actually was just using you.
[00:00:48]
Oh.
[00:00:50]
No, that was abusing me.
[00:00:52]
Like, definitely.
[00:00:54]
Not entirely sure of the definition
[00:00:56]
of that word, but
[00:00:58]
now I feel abused.
[00:01:00]
At least feel used.
[00:01:02]
Well, Jeroen, how
[00:01:04]
do you make sure that your
[00:01:06]
code is used
[00:01:08]
while also avoiding abusing
[00:01:10]
your code, because we wouldn't want that.
[00:01:12]
And what are we talking about today?
[00:01:14]
Well, we're
[00:01:16]
talking about
[00:01:18]
techniques, technical
[00:01:20]
practices that help you avoid unused code.
[00:01:22]
Unused code?
[00:01:24]
Do you have thoughts and opinions
[00:01:26]
on unused code?
[00:01:28]
Not really.
[00:01:30]
Maybe I have
[00:01:32]
a blog post somewhere
[00:01:34]
or two or
[00:01:36]
four and
[00:01:38]
four different
[00:01:40]
presentations on it.
[00:01:42]
And
[00:01:44]
five packages about unused code.
[00:01:46]
But no, I wouldn't say I have
[00:01:48]
any thoughts
[00:01:50]
on that. Not much.
[00:01:52]
You've kind of carved out a niche
[00:01:54]
for yourself with unused code.
[00:01:56]
Or perhaps with used code, I don't know.
[00:01:58]
Destroying unused code?
[00:02:00]
Obliterating unused code?
[00:02:02]
Definitely.
[00:02:04]
This is not
[00:02:06]
what I wanted to do with ElmReview.
[00:02:08]
I didn't think
[00:02:10]
unused code would be such a focus.
[00:02:12]
It just does it
[00:02:14]
so well that it kind of became it.
[00:02:16]
It became its trademark
[00:02:18]
in a kind of way.
[00:02:20]
Elm is too good at
[00:02:22]
calling you out when you have unused code.
[00:02:24]
Because it's not like, oh well it might
[00:02:26]
get called somewhere by some
[00:02:28]
magic reflection access.
[00:02:30]
Nope. It's not used.
[00:02:32]
Done.
[00:02:34]
Let's go to the next issue.
[00:02:36]
Also not used. Remove it.
[00:02:38]
Boom. Gone.
[00:02:40]
So, maybe before
[00:02:42]
we dive into unused code,
[00:02:44]
I wanted to touch on
[00:02:46]
Abused code?
[00:02:48]
I'm very curious what the definition of that
[00:02:50]
would be. Me too.
[00:02:52]
Where do
[00:02:54]
we find unused code?
[00:02:56]
In an Elm app?
[00:02:58]
In your source code.
[00:03:00]
Source code is a common offender.
[00:03:02]
Yeah. I think another
[00:03:04]
place that we find unused code
[00:03:06]
within your source code
[00:03:08]
is in comments.
[00:03:10]
This is an interesting topic because ElmReview
[00:03:12]
does not look at these
[00:03:14]
at the moment. It's possible that it
[00:03:16]
could, but it would require some heuristics
[00:03:18]
because for all it knows, it could
[00:03:20]
not be code.
[00:03:22]
You mean like trying to find
[00:03:24]
comments that are
[00:03:26]
commented out code, right?
[00:03:28]
I actually worked on a rule for that
[00:03:30]
I think for ESLint.
[00:03:32]
And I think the result
[00:03:34]
was that
[00:03:36]
it sometimes got things wrong.
[00:03:38]
Like if you had a comment
[00:03:40]
that was just plain English
[00:03:42]
without punctuation
[00:03:44]
or something, then it looked
[00:03:46]
like just a function call
[00:03:48]
or something.
[00:03:50]
Especially if it didn't start with an uppercase
[00:03:52]
letter, then it
[00:03:54]
looked like code.
[00:03:56]
But that was just a comment. So yeah, as you say
[00:03:58]
plenty of false positives.
[00:04:00]
But doable, I guess.
[00:04:02]
You know what my favorite places
[00:04:04]
for unused code are?
[00:04:06]
Tests. I do
[00:04:08]
like... At that point
[00:04:10]
it's used, arguably.
[00:04:12]
I love unused code in
[00:04:14]
version control. I think that's a great
[00:04:16]
place to store it.
[00:04:18]
Remove it
[00:04:20]
and find it again.
[00:04:22]
I also think that
[00:04:24]
it's reasonable to
[00:04:26]
just put something in
[00:04:28]
your notes manager.
[00:04:30]
If you just have some
[00:04:32]
interesting tidbit and you're like, I'm not sure
[00:04:34]
I want to lose this. You want to have it for
[00:04:36]
reference? Just throw it in a note.
[00:04:38]
That's fine.
[00:04:40]
I would be concerned if someone was
[00:04:42]
doing that too much.
[00:04:44]
But... Yeah, you're thinking
[00:04:46]
for instance, like utility functions, right?
[00:04:48]
Like if you need a
[00:04:50]
find function for lists or something.
[00:04:52]
Or if it's like some code
[00:04:54]
that I'm uncomfortable parting
[00:04:56]
ways with because I'm like,
[00:04:58]
I think I want to do something with this at
[00:05:00]
some point. Or better
[00:05:02]
yet, delete it. It's in
[00:05:04]
version control. And then maybe
[00:05:06]
in your notes app, maybe you
[00:05:08]
have a link to the diff from
[00:05:10]
that in version control.
[00:05:12]
Or you... Well, the diff
[00:05:14]
is in a patch, right?
[00:05:16]
And patches
[00:05:18]
or git patches can be
[00:05:20]
stored as files. Yes.
[00:05:22]
Git patches can be stored as files or a github
[00:05:24]
link. Github link to
[00:05:26]
commit. Yeah, absolutely. So first
[00:05:28]
of all, so we're going to talk
[00:05:30]
about how to
[00:05:32]
avoid unused code
[00:05:34]
and practices to
[00:05:36]
minimize that. But
[00:05:38]
why do we care so
[00:05:40]
much about unused code?
[00:05:42]
And avoiding having that?
[00:05:44]
Because it feels
[00:05:46]
good to have all those
[00:05:48]
negative diffs in
[00:05:50]
github. That's true.
[00:05:52]
It just
[00:05:54]
feels good to remove code.
[00:05:56]
Which is so weird.
[00:05:58]
Because I know that when you're
[00:06:00]
a beginner, you write a lot
[00:06:02]
of code. Often it's your code because
[00:06:04]
you're working on projects
[00:06:06]
alone because that's
[00:06:08]
how your projects at school work.
[00:06:10]
Because you're exploring it
[00:06:12]
on your own.
[00:06:14]
And then if you ever need to remove
[00:06:16]
code that you wrote,
[00:06:18]
it feels bad. It feels like, oh, well,
[00:06:20]
I didn't think about this
[00:06:22]
well enough in the first place.
[00:06:24]
Which is true, but also
[00:06:26]
maybe it was
[00:06:28]
right for the time.
[00:06:30]
And yeah, as you grow more experienced, for some
[00:06:32]
reason, it feels good to delete
[00:06:34]
code. And I actually
[00:06:36]
wonder why?
[00:06:38]
Maybe it's just because
[00:06:40]
we know that all the code that we
[00:06:42]
have in a codebase,
[00:06:44]
we need to maintain it.
[00:06:46]
And we don't like maintaining it.
[00:06:48]
So whenever we can delete code,
[00:06:50]
we're like, okay, well, this is a lot of code
[00:06:52]
that I don't need to maintain anymore.
[00:06:54]
I would say that's it.
[00:06:56]
I think that's definitely the case
[00:06:58]
for me. And I think also
[00:07:00]
I think I've talked about this
[00:07:02]
Linus Torvald's definition of
[00:07:04]
elegance in coding, and how
[00:07:06]
he thinks that that's one of the main
[00:07:08]
skills of an
[00:07:10]
experienced coder,
[00:07:12]
is being able to identify
[00:07:14]
when his definition
[00:07:16]
of elegance being
[00:07:18]
identifying when a special
[00:07:20]
case can be folded in
[00:07:22]
to a single case. So you take, oh,
[00:07:24]
there was this case, if this, then that, if this,
[00:07:26]
then that. And you're like, oh, this is actually just
[00:07:28]
a special case of the same thing.
[00:07:30]
So I can actually handle this in the
[00:07:32]
same code path if I
[00:07:34]
re-architect
[00:07:36]
the way this is happening a little bit.
[00:07:38]
So I think that
[00:07:40]
that's a sign of your code
[00:07:42]
becoming more elegant when you're starting to get
[00:07:44]
unused code paths. It's also a sign
[00:07:46]
of your product becoming more elegant
[00:07:48]
in the same type of way when
[00:07:50]
you realize this feature
[00:07:52]
can actually be supported through
[00:07:54]
a smaller set of
[00:07:56]
primitives in our application
[00:07:58]
for the user. Yeah. Like, this case
[00:08:00]
can handle both of these
[00:08:02]
edge cases at once
[00:08:04]
in a nicer
[00:08:06]
way. Yeah, exactly.
[00:08:08]
So, you know, yeah, the interface
[00:08:10]
for creating a
[00:08:12]
post and creating a comment, maybe
[00:08:14]
we can reuse some of these things. And that's
[00:08:16]
intuitive for the user, and it's
[00:08:18]
intuitive, you know. So, removing
[00:08:20]
those types of special cases,
[00:08:22]
we know it's going to make less maintenance burden,
[00:08:24]
we know that when we're
[00:08:26]
changing things, we can trust that they're changing
[00:08:28]
in the same place. It reduces the
[00:08:30]
cognitive load, because we
[00:08:32]
don't have to think about what all these different
[00:08:34]
pieces are doing. Yeah.
[00:08:36]
And I agree about the part
[00:08:38]
you said, which is basically
[00:08:40]
about simplifying the code. The more
[00:08:42]
you remove unused code, the more
[00:08:44]
you can notice that
[00:08:46]
some things are simpler than they
[00:08:48]
were before, and then
[00:08:50]
you can simplify them even
[00:08:52]
more, and then notice new simplifications,
[00:08:54]
new unused code.
[00:08:56]
And, yeah, every time
[00:08:58]
I create a new Elmer's View rule to
[00:09:00]
find unused code, I'm
[00:09:02]
hoping that it will create a snowball
[00:09:04]
effect. Like, just start
[00:09:06]
somewhere, and then you notice, oh, well, this thing
[00:09:08]
is not used anymore. Oh, and this is also
[00:09:10]
not used. Oh, and this, that means that
[00:09:12]
this is also not used. And then you remove
[00:09:14]
two whole modules and
[00:09:16]
a dependency and
[00:09:18]
300
[00:09:20]
lines of code, or
[00:09:22]
3000, I don't know. It just feels
[00:09:24]
good. Yeah. Again, because
[00:09:26]
less maintenance, and the code is
[00:09:28]
now simpler and more maintainable.
[00:09:30]
Honestly, there's not much
[00:09:32]
that is bad about it.
[00:09:34]
The only
[00:09:36]
thing I would say is, what
[00:09:38]
we mentioned before, is like, well,
[00:09:40]
if you ever want to
[00:09:42]
recover that code, if you want to
[00:09:44]
reuse it,
[00:09:46]
even though you've just deleted it,
[00:09:48]
well, then it's going to be painful.
[00:09:50]
Like, we'll talk about it later,
[00:09:52]
but there are techniques to recover
[00:09:54]
that, like using Git, using
[00:09:56]
notes, which in practice, I don't
[00:09:58]
ever need to use.
[00:10:00]
Like, in one of my
[00:10:02]
blog posts about removing
[00:10:04]
dead code with Elmer's
[00:10:06]
View, so that's called safe
[00:10:08]
dead code removal.
[00:10:10]
Wait, what is it called again?
[00:10:12]
Safe dead code removal
[00:10:14]
in a pure functional language.
[00:10:16]
I talk about
[00:10:18]
YACNI, so that is, you ain't
[00:10:20]
going to need it, depending on
[00:10:22]
pronunciation up to your
[00:10:24]
regional accent.
[00:10:26]
You ain't going to need it, or something.
[00:10:28]
I don't know. This is the
[00:10:30]
Parisian Dutch variant of
[00:10:32]
that phrase.
[00:10:34]
I was going for the Texan accent.
[00:10:36]
I guess.
[00:10:40]
Yeah, so
[00:10:42]
you ain't going to need it is about,
[00:10:44]
like, you wrote a lot of code
[00:10:46]
that was used before, or that
[00:10:48]
you want to use in the future,
[00:10:50]
and the idea is that
[00:10:52]
you are not going to need it
[00:10:54]
in practice.
[00:10:56]
Because very often,
[00:10:58]
the cases that you need to support,
[00:11:00]
that you want to
[00:11:02]
support with that
[00:11:04]
now unused code,
[00:11:06]
are not going to appear again, or
[00:11:08]
are not going to appear in that shape.
[00:11:10]
Right, that's a great
[00:11:12]
distinction. Yeah, so
[00:11:14]
you think, oh, I'm going to need,
[00:11:16]
like, I'm building a form
[00:11:18]
API, and I'm going to have
[00:11:20]
text inputs, I'm going to have
[00:11:22]
password inputs,
[00:11:24]
and that works great, and then
[00:11:26]
at some point I'm going to think, oh, well,
[00:11:28]
I'm probably going to have, like, radio button
[00:11:30]
inputs, so I'm going to add support for
[00:11:32]
those. And
[00:11:34]
that's going to be a lot of work, because it's
[00:11:36]
a new kind of input,
[00:11:38]
and no one ever uses it.
[00:11:40]
So, like, well, first of all,
[00:11:42]
you now have code that you're not entirely
[00:11:44]
sure that it works.
[00:11:46]
You can write tests, you can have
[00:11:48]
end-to-end tests with Cypress,
[00:11:50]
and that gives you a lot of optimism about
[00:11:52]
whether it works or not.
[00:11:54]
But it might have bugs that you
[00:11:56]
didn't catch. And then at some
[00:11:58]
point you notice, okay, well,
[00:12:00]
I finally need it.
[00:12:02]
And you try to implement it, and you're like,
[00:12:04]
well, actually, I need a checkbox.
[00:12:06]
That feels much better here.
[00:12:08]
Yeah, so
[00:12:10]
what you wanted to support,
[00:12:12]
turns out you needed to support it in a different
[00:12:14]
way than you originally thought.
[00:12:16]
And now you still have all that
[00:12:18]
code about supporting radio buttons
[00:12:20]
that is not necessary, that
[00:12:22]
has a lot of complexity, and that you need
[00:12:24]
to maintain. Exactly.
[00:12:26]
It basically, like, you're
[00:12:28]
bound to this
[00:12:30]
design that
[00:12:32]
wasn't necessarily the optimal
[00:12:34]
design. It was just this
[00:12:36]
initial path you went
[00:12:38]
down. So you're tying yourself
[00:12:40]
down to every
[00:12:42]
possible thing. It's like
[00:12:44]
being,
[00:12:46]
having to be backwards compatible
[00:12:48]
to MS-DOS from
[00:12:50]
1992
[00:12:52]
forever.
[00:12:54]
And now you can't
[00:12:56]
change your design to support
[00:12:58]
all these very sensible things, because
[00:13:00]
you're tied down to that. And of course,
[00:13:02]
being backwards
[00:13:04]
compatible for users
[00:13:06]
and not breaking their stuff has value.
[00:13:08]
But being backwards
[00:13:10]
compatible, basically, with
[00:13:12]
your old code
[00:13:14]
that you wrote just in case for this thing
[00:13:16]
you thought you would need in the future, does not
[00:13:18]
have value. So you're tying yourself down
[00:13:20]
to a design
[00:13:22]
for no value. And so
[00:13:24]
if you can avoid that in your
[00:13:26]
workflow, then you can
[00:13:28]
be much more free in the way that you
[00:13:30]
design your code and your
[00:13:32]
features.
[00:13:34]
One of the reasons why we say that Elm
[00:13:36]
is so nice to work with
[00:13:38]
is because it's so maintainable. And it's
[00:13:40]
so maintainable because it makes it
[00:13:42]
easy to refactor and to change
[00:13:44]
your code. But if you're not allowed
[00:13:46]
to change your code because you want to keep
[00:13:48]
things as they are
[00:13:50]
today or as they were yesterday,
[00:13:52]
well then,
[00:13:54]
you're limiting yourself
[00:13:56]
to doing
[00:13:58]
a better job, basically.
[00:14:00]
You're putting
[00:14:02]
weight on your ankles that don't feel
[00:14:04]
necessary.
[00:14:06]
Right. And I think that
[00:14:08]
it's understandable
[00:14:10]
why that happens. So maybe let's dig into
[00:14:12]
how do we get there?
[00:14:14]
If we agree that
[00:14:16]
unused code
[00:14:18]
ties you down in an undesirable
[00:14:20]
way, why do we get into that state
[00:14:22]
in the first place? And
[00:14:24]
what's happening when
[00:14:26]
on a recent
[00:14:28]
ElmTown episode,
[00:14:30]
Wolfgang and Jared were talking
[00:14:32]
about how it can sometimes
[00:14:34]
be difficult when you're introducing some
[00:14:36]
of these Elm review rules for
[00:14:38]
no unused code.
[00:14:40]
It can sometimes be difficult to get
[00:14:42]
your coworkers to buy into
[00:14:44]
that process because they
[00:14:46]
say, well, okay, no
[00:14:48]
unused code, fine, but I'm
[00:14:50]
going to use this code. So how does
[00:14:52]
that happen? Right? So
[00:14:54]
how do you get into that state? How do you end up with
[00:14:56]
unused code? Why does that happen?
[00:14:58]
Yes. So I
[00:15:00]
see at least two
[00:15:02]
ways. One, you had
[00:15:04]
code that was used and then
[00:15:06]
turns out you
[00:15:08]
don't use it anymore for
[00:15:10]
several reasons. Like one
[00:15:12]
is, well, you wrote
[00:15:14]
code that didn't work
[00:15:16]
or you wrote code
[00:15:18]
for a feature that
[00:15:20]
you removed because it was
[00:15:22]
prematurely designed.
[00:15:24]
Like, oh, we're going to need
[00:15:26]
this feature. Oh, it turns out, no,
[00:15:28]
none of your users are using it.
[00:15:30]
Let's remove it. Okay, let's remove it.
[00:15:32]
Well, then you have dead code, remove it.
[00:15:34]
And yes, things like that, you
[00:15:36]
had some code, you wrote things differently
[00:15:38]
now, and those code
[00:15:40]
paths are never used anymore. The
[00:15:42]
other way is that
[00:15:44]
you are prematurely
[00:15:46]
introducing code
[00:15:48]
because you're expecting
[00:15:50]
them to be used or to be useful
[00:15:52]
later on. So
[00:15:54]
again, the example of the form is
[00:15:56]
I think I'm going to need radio
[00:15:58]
buttons. Let's add them
[00:16:00]
now. Let's add the complexity
[00:16:02]
for that now
[00:16:04]
so that my life
[00:16:06]
in a week will be easier
[00:16:08]
or the life of my
[00:16:10]
fellow developers who have not looked at
[00:16:12]
the implementation of this form API
[00:16:14]
will be easier and they don't have to look
[00:16:16]
at it. They can just
[00:16:18]
start working on the form
[00:16:20]
whether they need radio buttons or not.
[00:16:22]
But I think they're
[00:16:24]
going to need it. So yeah, I
[00:16:26]
see those two reasons
[00:16:28]
mostly. Yeah.
[00:16:30]
I think this is actually a bit
[00:16:32]
more subtle in cases like this.
[00:16:34]
I'm curious what you think because... Oh, there's plenty
[00:16:36]
of subtlety. Yeah. Go ahead.
[00:16:38]
So like, if you have something
[00:16:40]
that is essentially
[00:16:42]
an internal package,
[00:16:44]
like a form package,
[00:16:46]
or, you know,
[00:16:48]
a button builder,
[00:16:50]
and, you know, let's say you have
[00:16:52]
button.withSize
[00:16:54]
small, medium, large
[00:16:56]
or button.withSmall
[00:16:58]
or something like that. And it's like, well,
[00:17:00]
medium is never used.
[00:17:02]
Only small and large, right?
[00:17:04]
Then the question
[00:17:06]
is, does that represent
[00:17:08]
part of our design system
[00:17:10]
that is useful,
[00:17:12]
which is not useful
[00:17:14]
right now because we haven't needed it yet,
[00:17:16]
but is going to be useful?
[00:17:18]
And this is just a
[00:17:20]
logical thing to include?
[00:17:22]
Or is it, we're actually
[00:17:24]
prematurely introducing this piece
[00:17:26]
of the design system? And
[00:17:28]
I think you can make a case
[00:17:30]
for either. I think
[00:17:32]
in some cases there are very clear cases
[00:17:34]
where it's just like, you know,
[00:17:36]
okay, we, you know,
[00:17:38]
we're designing something
[00:17:40]
that follows a spec. You know,
[00:17:42]
the Open Graph
[00:17:44]
tags for SEO tags
[00:17:46]
for sharing links on
[00:17:48]
Twitter or
[00:17:50]
x.com, whatever it may be.
[00:17:52]
You know.
[00:17:54]
Can you tell when we're recording?
[00:17:56]
Yeah.
[00:17:58]
And so, okay,
[00:18:00]
Open Graph tags have,
[00:18:02]
you know, these different variants
[00:18:04]
that are defined in a specification.
[00:18:06]
There are small
[00:18:08]
and large, and there are these four
[00:18:10]
different things you can define.
[00:18:12]
And we're just exposing an API
[00:18:14]
for that, right? So you may end up
[00:18:16]
with an unused thing
[00:18:18]
if you publish that in a package.
[00:18:20]
Like, I sometimes see that when I'm
[00:18:22]
developing code that
[00:18:24]
it's like, well, this is unused.
[00:18:26]
So it's like, well, yeah,
[00:18:28]
but this is part of the specification, and I
[00:18:30]
definitely want it there because
[00:18:32]
I'm just following the spec.
[00:18:34]
Yeah. Well,
[00:18:36]
this is like
[00:18:38]
complex in a way because
[00:18:40]
now it's not about code
[00:18:42]
in a way because
[00:18:44]
you're adapting to a
[00:18:46]
spec, which makes
[00:18:48]
a lot of sense in my opinion,
[00:18:50]
but that spec has
[00:18:52]
unused things. So you're just
[00:18:54]
moving where the
[00:18:56]
unused things are. So now it's not
[00:18:58]
part of the developers'
[00:19:00]
job where
[00:19:02]
they introduced unused code or they
[00:19:04]
did things prematurely.
[00:19:06]
It's the designer.
[00:19:08]
And you could probably say,
[00:19:10]
well, Yagni
[00:19:12]
works just as
[00:19:14]
well for you as a
[00:19:16]
designer as for me as a developer.
[00:19:18]
So if you don't
[00:19:20]
intend to use those things, then
[00:19:22]
don't design them.
[00:19:24]
And, yeah, I mean,
[00:19:26]
Yagni works
[00:19:28]
here just as well.
[00:19:30]
You might use it,
[00:19:32]
you might not use it.
[00:19:34]
I'm sure that in
[00:19:36]
some of the design
[00:19:38]
tools, you have ways to
[00:19:40]
recover old designs or you can
[00:19:42]
just put them in a separate file
[00:19:44]
or a separate design file.
[00:19:46]
So, yeah, I would probably say
[00:19:48]
this is mostly an issue about
[00:19:50]
your design team
[00:19:52]
and you
[00:19:54]
and your communication with them.
[00:19:56]
That said, if you have
[00:19:58]
a specification
[00:20:00]
where, for instance, you have a
[00:20:02]
at your company, you have one design
[00:20:04]
team or one design
[00:20:06]
style, rather, for
[00:20:08]
all the products, and one of
[00:20:10]
the products is written React, and they use
[00:20:12]
all the things in the spec.
[00:20:14]
Right, exactly.
[00:20:16]
And in your Elm code, you're only using a portion
[00:20:18]
of it. Well, yeah,
[00:20:20]
those things are
[00:20:22]
used just not in this code base.
[00:20:24]
Exactly, and I would be
[00:20:26]
inclined to make an exception for those and say,
[00:20:28]
you know what, this is, yes, it's
[00:20:30]
unused, but maybe it's
[00:20:32]
actually just, like, literally
[00:20:34]
using a string.
[00:20:36]
I mean, you could definitely argue, like, well,
[00:20:38]
okay, why
[00:20:40]
don't you use them in
[00:20:42]
some tests or in an
[00:20:44]
Elmbook example or a
[00:20:46]
whatever, you know, storybook example or
[00:20:48]
somewhere. Yeah,
[00:20:50]
I mean, you can also say, like,
[00:20:52]
well, I have a spec,
[00:20:54]
but is my implementation correct?
[00:20:56]
And you can only know that
[00:20:58]
if you use the code. If you're using it, exactly.
[00:21:00]
So you could probably just
[00:21:02]
delete it and recover it later
[00:21:04]
when you need it or just not
[00:21:06]
write it, you know.
[00:21:08]
What you just said, like,
[00:21:10]
brings me to something that I'm working on right
[00:21:12]
now, and maybe it will be
[00:21:14]
released by the time that
[00:21:16]
this episode airs.
[00:21:18]
You said,
[00:21:20]
if you want something to be
[00:21:22]
marked as used or not reported by
[00:21:24]
Elm Review, you can write a test for
[00:21:26]
it or you can add an
[00:21:28]
example in a style guide
[00:21:30]
in a storybook
[00:21:32]
or something like that. And I'm
[00:21:34]
at the moment working on
[00:21:36]
making
[00:21:38]
the no-unused
[00:21:40]
exports rule report things
[00:21:42]
that are only used in those files.
[00:21:44]
So if you have a function
[00:21:46]
that you can only find
[00:21:48]
in test code, for instance,
[00:21:50]
then it's going to be reported.
[00:21:52]
So writing a test
[00:21:54]
for it is not going to save you
[00:21:56]
anymore. That's
[00:21:58]
the idea. This is going to be
[00:22:00]
opt-in because
[00:22:02]
unfortunately this is going to give some
[00:22:04]
false positives because
[00:22:06]
sometimes
[00:22:08]
you write test helpers that are in
[00:22:10]
the production code but to enable tests
[00:22:12]
like, for instance, for when you have
[00:22:14]
opaque types. So
[00:22:16]
you're going to have to annotate them, which is
[00:22:18]
not great, but
[00:22:20]
so this is something that you
[00:22:22]
will be able to opt-in
[00:22:24]
to. If you want
[00:22:26]
to go the extra mile of like, we really
[00:22:28]
don't want unused code,
[00:22:30]
let's put in some
[00:22:32]
extra effort into
[00:22:34]
tagging the test helpers
[00:22:36]
and stuff like that
[00:22:38]
as such and the rest can be
[00:22:40]
removed. And I think
[00:22:42]
that will be pretty good.
[00:22:44]
That will be pretty useful. But as
[00:22:46]
you say, I'm
[00:22:48]
trying this out
[00:22:50]
on my project at work and
[00:22:52]
for instance, well, plenty of
[00:22:54]
our UI components
[00:22:56]
are unused.
[00:22:58]
Like, we have
[00:23:00]
like, I don't know,
[00:23:02]
600 or 500
[00:23:04]
icons that our designer
[00:23:06]
made. Turns out we only use 200.
[00:23:08]
Well, at least now we know.
[00:23:10]
And now we can talk to
[00:23:12]
our designer and tell them,
[00:23:14]
hey, these 200
[00:23:16]
or 300 icons are never
[00:23:18]
used. Is that on purpose?
[00:23:20]
Do you think we should remove
[00:23:22]
them? Maybe that will help you
[00:23:24]
do less work as a designer.
[00:23:26]
Exactly. Yeah.
[00:23:28]
And what's going on in that process?
[00:23:30]
That there's,
[00:23:32]
are these icons being designed
[00:23:34]
that are never used? So is it
[00:23:36]
that the developers accidentally use
[00:23:38]
the wrong icon? That's possible.
[00:23:40]
Or is it that the designers
[00:23:42]
are designing something for
[00:23:44]
a bunch of
[00:23:46]
ideas for features that are
[00:23:48]
then never actually shipped
[00:23:50]
and then the features that get shipped
[00:23:52]
have icons that are used. So
[00:23:54]
I agree with you that you've got to think
[00:23:56]
about the
[00:23:58]
process, not just the coding process
[00:24:00]
but the design process.
[00:24:02]
Yeah, and definitely there needs to be some
[00:24:04]
communication to know
[00:24:06]
what is the expectation?
[00:24:08]
Is this icon actually supposed to be used?
[00:24:10]
And if so, why are we not
[00:24:12]
using it? And that's a conversation you
[00:24:14]
want to have.
[00:24:16]
That's the same thing with developers.
[00:24:18]
So for instance, when I go to a
[00:24:20]
new part of our
[00:24:22]
code base at work or
[00:24:24]
a project that I don't know about
[00:24:26]
and I start removing code, I'm like
[00:24:28]
or simplifying it or
[00:24:30]
changing it, I'm always like
[00:24:32]
is this how
[00:24:34]
things are supposed to be?
[00:24:36]
Was there a reason why we made
[00:24:38]
this function or why we
[00:24:40]
wrote code this way?
[00:24:42]
And often I
[00:24:44]
feel a bit stuck because
[00:24:46]
I feel like I don't have the whole
[00:24:48]
story and maybe I should just remove it
[00:24:50]
and talk to them afterwards
[00:24:52]
or before.
[00:24:54]
At some point it would be nice if I could
[00:24:56]
talk to them and
[00:24:58]
figure out what the best way
[00:25:00]
forward is. So that's
[00:25:02]
one of the reasons why
[00:25:04]
there's the ElmReviewSuppress
[00:25:06]
feature where you
[00:25:08]
can just say well all these errors that I have
[00:25:10]
for this or that
[00:25:12]
rule or all the rules,
[00:25:14]
let's just ignore them for now.
[00:25:16]
Which I think of
[00:25:18]
as identifying
[00:25:20]
technical debt in a way.
[00:25:22]
Because now you see, okay
[00:25:24]
well we have 200 suppressed errors.
[00:25:26]
Well those are
[00:25:28]
200 technical debts
[00:25:30]
mentions, reports.
[00:25:32]
And let's figure them out at
[00:25:34]
some point through
[00:25:36]
grant work or
[00:25:38]
communication with other developers
[00:25:40]
or designers.
[00:25:42]
And there is a cost.
[00:25:44]
This process you're describing,
[00:25:46]
you do kind of have to have those
[00:25:48]
conversations because it's hard to know the intention.
[00:25:50]
Was this
[00:25:52]
at the time I thought this would come in
[00:25:54]
handy down the road, but it turns out
[00:25:56]
it's fine we can delete it now. Or it's like, well
[00:25:58]
I thought it would come in handy down the
[00:26:00]
road. I ended up not needing it.
[00:26:02]
But we're going to need to check if anybody
[00:26:04]
else decided to use it and decided
[00:26:06]
to depend on it. So that's
[00:26:08]
one of the illustrations
[00:26:10]
of why it is very costly to have
[00:26:12]
unused code.
[00:26:14]
And
[00:26:16]
extra complexity. Because
[00:26:18]
are people
[00:26:20]
starting to depend on
[00:26:22]
these things? Are they starting to
[00:26:24]
build their process in a way where they're
[00:26:26]
expecting these things
[00:26:28]
to be sitting around?
[00:26:30]
As you said, if I
[00:26:32]
introduce unused code
[00:26:34]
and then someone else
[00:26:36]
wants to clean up or wants
[00:26:38]
to change some kind of behavior,
[00:26:40]
well they need to go through me.
[00:26:42]
If that code was not there,
[00:26:44]
well we wouldn't need to have communication.
[00:26:46]
So it is
[00:26:48]
some kind of depth, technical or
[00:26:50]
process
[00:26:52]
or team.
[00:26:54]
Exactly. And a lot of it does come down
[00:26:56]
to the process I think. So let's talk about
[00:26:58]
that. So when I think about
[00:27:00]
unused code, the
[00:27:02]
big thing on my mind,
[00:27:04]
and we've talked about some more subtle corner cases
[00:27:06]
like
[00:27:08]
having something that actually represents
[00:27:10]
part of a spec that you're
[00:27:12]
going to use. There are
[00:27:14]
other subtle cases.
[00:27:16]
The unsubtle case
[00:27:18]
that is at the front of my mind
[00:27:20]
when I'm thinking about unused code
[00:27:22]
is a process
[00:27:24]
for building code that
[00:27:26]
is thinking about things
[00:27:28]
you're going to need later and
[00:27:30]
building out code to try
[00:27:32]
and make it efficient and saying
[00:27:34]
well while I'm in here
[00:27:36]
I'm going to write this code.
[00:27:38]
I'm not using it yet. I might not
[00:27:40]
use it for a while, but while I'm thinking
[00:27:42]
about this I'm going to go ahead and write it.
[00:27:44]
I might not use it for a while, but I'm going to
[00:27:46]
write it. And I think
[00:27:48]
this is
[00:27:50]
what's going on with this type of process
[00:27:52]
is it's
[00:27:54]
juggling unfinished work. And there's
[00:27:56]
a big cost to that because
[00:27:58]
if code is unused it is
[00:28:00]
unfinished, right? Like you haven't
[00:28:02]
shipped it anywhere. So it's
[00:28:04]
work in progress.
[00:28:06]
But if you wrote tests
[00:28:08]
for it you could also say well
[00:28:10]
this is the exact moment where
[00:28:12]
you should write that code because
[00:28:14]
you're in the zone or
[00:28:16]
you have all the things in your mind
[00:28:18]
and you're never going to have a better
[00:28:20]
time to do this in a
[00:28:22]
way. Because you don't have to relearn
[00:28:24]
it now because you have everything
[00:28:26]
in your mind. If you do this, if
[00:28:28]
you add this feature in a week
[00:28:30]
then you're going to have to do that.
[00:28:32]
That said, that is basically
[00:28:34]
our job. Go to
[00:28:36]
some part of the codebase and add
[00:28:38]
new things. So
[00:28:40]
we should be able to do this easily
[00:28:42]
anyway. Right, and if you're working in that
[00:28:44]
way then you might end
[00:28:46]
up introducing a lot of things
[00:28:48]
that you think you'll need later
[00:28:50]
that, I mean we're
[00:28:52]
talking about unused top
[00:28:54]
level definitions and unused
[00:28:56]
custom type variants and the sort of things
[00:28:58]
that Elm Review can identify but
[00:29:00]
what about an unused
[00:29:02]
code path, right? Like a dead code path
[00:29:04]
is something that
[00:29:06]
at the moment Elm Review can
[00:29:08]
only identify if it's a
[00:29:10]
degenerate case or it's like
[00:29:12]
if false. Then Elm Review Simplify
[00:29:14]
can identify that.
[00:29:16]
There's some that we
[00:29:18]
also can do. Right.
[00:29:20]
Or and false and things like that, right?
[00:29:22]
No, no, like if you have
[00:29:24]
if a and then
[00:29:26]
under that you have if a again
[00:29:28]
then it knows that's going to be true always.
[00:29:30]
Right, and that's awesome
[00:29:32]
but that's still pretty
[00:29:34]
narrow. It doesn't know what
[00:29:36]
values will actually be flowing through the system
[00:29:38]
and it may be that
[00:29:40]
you're never going to get this type of value.
[00:29:42]
So that's another type of unused code.
[00:29:44]
So when you're introducing
[00:29:46]
this is an even more
[00:29:48]
costly type of
[00:29:50]
unused code to maintain because
[00:29:52]
you don't even know where it is
[00:29:54]
and you look at this code and you're like
[00:29:56]
wait a minute, is this even possible in our codebase?
[00:29:58]
And now you have to have that conversation
[00:30:00]
and you need to try to figure out
[00:30:02]
is it used? So
[00:30:04]
that's even more costly to introduce that type of
[00:30:06]
unused code. But it's
[00:30:08]
this mindset of
[00:30:10]
I'll introduce these things
[00:30:12]
that I think I'll need down the road
[00:30:14]
as you introduce these things
[00:30:16]
it seems efficient at the time
[00:30:18]
but you're bogging down the process
[00:30:20]
by tying yourself
[00:30:22]
to these decisions
[00:30:24]
that aren't serving
[00:30:26]
you. So it's a balancing
[00:30:28]
act. It might seem like it's efficient
[00:30:30]
because you have context
[00:30:32]
on it now and you're working on it now
[00:30:34]
but you have to remember that
[00:30:36]
you're going to now be looking
[00:30:38]
at that code, asking yourself that question
[00:30:40]
a few months from now and
[00:30:42]
if you have that
[00:30:44]
way of working, that process
[00:30:46]
now you're going to be incurring that
[00:30:48]
tax over and over again.
[00:30:50]
So it's a difficult
[00:30:52]
mindset shift but I think that
[00:30:54]
there is another way. There is
[00:30:56]
a way to write code just in time
[00:30:58]
and it's a skill
[00:31:00]
that requires practice
[00:31:02]
and it's actually
[00:31:04]
not even a skill, it's a set of skills.
[00:31:06]
So it's easy to say
[00:31:08]
well, this is just more efficient
[00:31:10]
and it might be more efficient
[00:31:12]
with the skills
[00:31:14]
you have in your tool belt at the moment
[00:31:16]
but you have to step back
[00:31:18]
and say well
[00:31:20]
what if I picked up
[00:31:22]
a set of skills to help me with that?
[00:31:24]
Because often that's the answer.
[00:31:26]
Actually, another kind of step back
[00:31:28]
before we go into
[00:31:30]
the skills that you want to describe
[00:31:32]
like as people who write
[00:31:34]
APIs for people to use
[00:31:36]
often we spend
[00:31:38]
months or years
[00:31:40]
perfecting them
[00:31:42]
and therefore we know
[00:31:44]
we pretty much never
[00:31:46]
have the
[00:31:48]
perfect thing on the first draft
[00:31:50]
especially not when your mind
[00:31:52]
is in the zone because you don't
[00:31:54]
have any... you're not taking
[00:31:56]
a step back which is really useful
[00:31:58]
and that means that you're going to miss things
[00:32:00]
you're not going to see the full picture
[00:32:02]
and you're not going to revisit
[00:32:04]
ideas in a novel way
[00:32:06]
which is really useful
[00:32:08]
and helps so much with polishing
[00:32:10]
designs. And in practice
[00:32:12]
when you work with ElmCode
[00:32:14]
you often just go
[00:32:16]
through your code and you're like oh this is not how you
[00:32:18]
should write your code, this is how you
[00:32:20]
should do it. So let me rename
[00:32:22]
this function, let me change the arguments
[00:32:24]
and so on. And that's what we do
[00:32:26]
all day every day.
[00:32:28]
And yeah
[00:32:30]
if you are doing everything right now
[00:32:32]
and not when it's necessary
[00:32:34]
then you're not going to have
[00:32:36]
that step back, I don't know how
[00:32:38]
you'd say that. That allows you
[00:32:40]
to find a better solution.
[00:32:42]
Mhm.
[00:32:44]
Right. So, skill sets.
[00:32:46]
Right, yeah.
[00:32:48]
And it is a mindset shift of
[00:32:50]
trusting your future self
[00:32:52]
a little bit, you know. You have
[00:32:54]
to trust that you can...
[00:32:56]
Well I guess you can also
[00:32:58]
say like if you're doing the job
[00:33:00]
if you're working as a team on
[00:33:02]
something and you know that
[00:33:04]
part of the codebase better
[00:33:06]
and all the invariants
[00:33:08]
need to hold up and all the things that
[00:33:10]
need to be... how things
[00:33:12]
need to work, then you don't
[00:33:14]
want to push that work onto
[00:33:16]
another colleague of yours.
[00:33:18]
But again like
[00:33:20]
there are better ways out there like if you
[00:33:22]
want to have maintain invariants, you can
[00:33:24]
use update types and so on and so
[00:33:26]
on. There are techniques to
[00:33:28]
help you and your team
[00:33:30]
do what is necessary.
[00:33:32]
So unless your
[00:33:34]
colleague is a
[00:33:36]
beginner, I think
[00:33:38]
it's usually okay to just
[00:33:40]
wait. Right. So to me a lot of
[00:33:42]
these concepts come down to like
[00:33:44]
the idea of lean. Lean being
[00:33:46]
the idea of reducing
[00:33:48]
the cycle
[00:33:50]
time to actually
[00:33:52]
complete something and not
[00:33:54]
partially complete something. Actually
[00:33:56]
so until a user
[00:33:58]
has the feature in their
[00:34:00]
hands, it's not actually used.
[00:34:02]
And so lean has a
[00:34:04]
lot of concepts around this.
[00:34:06]
One of the concepts is
[00:34:08]
eyes for waste. Like being able
[00:34:10]
to perceive
[00:34:12]
where waste is coming from.
[00:34:14]
So if you're
[00:34:16]
building
[00:34:18]
some unused features,
[00:34:20]
being able to have
[00:34:22]
that sense that this is
[00:34:24]
costing me. This is
[00:34:26]
incurring a tax every
[00:34:28]
time I'm working on this code.
[00:34:30]
There's a cognitive load here, there's a maintenance burden,
[00:34:32]
there's a code review burden,
[00:34:34]
there's a
[00:34:36]
burden to writing
[00:34:38]
features to these constraints which might
[00:34:40]
not be necessary. So
[00:34:42]
that's one thing. And also
[00:34:44]
you want things to be
[00:34:46]
you want the feedback loop
[00:34:48]
to be as short as possible.
[00:34:50]
If you're creating unused code
[00:34:52]
you hinted at this earlier. You're
[00:34:54]
writing unused code, you don't actually
[00:34:56]
know if it works because you've never used it.
[00:34:58]
So that is a
[00:35:00]
real design smell.
[00:35:02]
You can have a pretty high
[00:35:04]
degree of confidence
[00:35:06]
but even with that
[00:35:08]
you might have bugs.
[00:35:10]
And if there's anything
[00:35:12]
that
[00:35:14]
I don't know, maybe
[00:35:16]
we have in common as Elm developers
[00:35:18]
it's a certain humility
[00:35:20]
about our own abilities.
[00:35:22]
We're like, we don't know better than
[00:35:24]
the compiler.
[00:35:26]
We want the compiler
[00:35:28]
to constrain us because we don't trust ourselves
[00:35:30]
because that's a type of
[00:35:32]
humility. We're like, no
[00:35:34]
compiler, help give
[00:35:36]
me sane constraints
[00:35:38]
and check things for me because I know
[00:35:40]
I can't trust myself because I'm just a human
[00:35:42]
and I make mistakes all the time.
[00:35:44]
Right?
[00:35:46]
Yeah, that's interesting.
[00:35:48]
I mean, I absolutely
[00:35:50]
agree and now I'm thinking
[00:35:52]
is that the reason why
[00:35:54]
plenty of people don't trust type systems?
[00:35:56]
Is because they have such a
[00:35:58]
high ego?
[00:36:00]
Maybe.
[00:36:02]
Maybe that's part of the reason.
[00:36:04]
Or maybe they play with other type systems.
[00:36:06]
Yeah, to me
[00:36:08]
I mean, this is, I don't know.
[00:36:10]
I think we have a lot of cognitive biases
[00:36:12]
and I think we have a lot of
[00:36:14]
reason to not trust ourselves
[00:36:16]
and I think that
[00:36:18]
using external tools as much as possible
[00:36:20]
to not have to trust ourselves
[00:36:22]
to me is an amazing thing. I love
[00:36:24]
working that way.
[00:36:26]
So having half-written code
[00:36:28]
that's never used
[00:36:30]
I don't trust it at all.
[00:36:32]
I don't trust it until I've
[00:36:34]
written some automated tests for it
[00:36:36]
and tried it out.
[00:36:38]
So if I have
[00:36:40]
half-written code
[00:36:42]
it's not running in production, it's not running
[00:36:44]
in a test, then
[00:36:46]
I'm just accruing all this code that
[00:36:48]
I have no idea if it works.
[00:36:50]
So I want to get
[00:36:52]
things to the definition of
[00:36:54]
done, whatever that means, as fast
[00:36:56]
as possible. And so it's really
[00:36:58]
a question of
[00:37:00]
I think a lot of it comes down to
[00:37:02]
do you want to work in horizontal slices
[00:37:04]
or vertical slices?
[00:37:06]
A lot of the time it feels more productive
[00:37:08]
to work in horizontal slices.
[00:37:10]
So basically a vertical
[00:37:12]
slice being
[00:37:14]
you can use it.
[00:37:16]
You have all the pieces, so like
[00:37:18]
do you have the front end, the back end
[00:37:20]
all these
[00:37:22]
pieces fitting together
[00:37:24]
or do you have, okay
[00:37:26]
I wrote the front end for this thing, now I just
[00:37:28]
need the API and well
[00:37:30]
in order to write the API endpoint
[00:37:32]
we're going to need some
[00:37:34]
warehouse step
[00:37:36]
that's doing this thing so we need to
[00:37:38]
ask this other team to do that
[00:37:40]
and a vertical slice
[00:37:42]
is just like, alright let's
[00:37:44]
build the simplest form of
[00:37:46]
this thing holistically that we can.
[00:37:48]
What's the simplest
[00:37:50]
back end processing
[00:37:52]
work we can do, what's the simplest
[00:37:54]
API we can write to get some
[00:37:56]
meaningful, valuable thing.
[00:37:58]
So we're doing everything but only
[00:38:00]
as much as necessary in the
[00:38:02]
sense that we're only going to do it
[00:38:04]
for this feature, we're not going to do
[00:38:06]
this other feature that we're thinking of
[00:38:08]
doing right after this. Exactly.
[00:38:10]
Yeah, so when you say like
[00:38:12]
oh I'm just going to keep this
[00:38:14]
simple and do a really small piece of work
[00:38:16]
what does that mean to you?
[00:38:18]
Does it mean I'm going to keep this really
[00:38:20]
simple and I'm going to
[00:38:22]
make this
[00:38:24]
I'm only going to do the
[00:38:26]
magic link authentication to start
[00:38:28]
because yes we
[00:38:30]
want to eventually add
[00:38:32]
OAuth providers for these
[00:38:34]
different services and we want to
[00:38:36]
do password authentication
[00:38:38]
and we want to do these different things but we also
[00:38:40]
want to do magic link authentication
[00:38:42]
and we can have only
[00:38:44]
that and then we don't need to build the
[00:38:46]
forgot password flow.
[00:38:48]
So it's just a way of
[00:38:50]
solving the puzzle in a way
[00:38:52]
where you can do one isolated
[00:38:54]
piece first. So it requires this mindset
[00:38:56]
and thought process where you're
[00:38:58]
you develop that skill
[00:39:00]
where you're able to prioritize things
[00:39:02]
based on how
[00:39:04]
independently doable they
[00:39:06]
are and how you can build
[00:39:08]
other things on top of them
[00:39:10]
and also
[00:39:12]
it being valuable because you're like well maybe
[00:39:14]
if we build magic authentication
[00:39:16]
magic link authentication maybe we
[00:39:18]
don't need password based authentication
[00:39:20]
can we get away with that?
[00:39:22]
It's
[00:39:24]
authentication isn't the most interesting example
[00:39:26]
but just doing this
[00:39:28]
thought process for your product
[00:39:30]
in general.
[00:39:32]
So that was vertical
[00:39:34]
slicing, what is horizontal?
[00:39:36]
Well it would be
[00:39:38]
I'm just going to build
[00:39:40]
the front end for this and when the back end team is ready
[00:39:42]
they'll ping me and let
[00:39:44]
me know the API is ready and then
[00:39:46]
I'll merge this pull request
[00:39:48]
And in the meantime I'm going to
[00:39:50]
mock the back end call or something
[00:39:52]
Yeah, mock it or
[00:39:54]
avoid calling the back end
[00:39:56]
avoid calling it, I'll just write the UI
[00:39:58]
for it and nothing's
[00:40:00]
going to be wired up but I'm going to write the UI
[00:40:02]
I'm going to get the designs for it
[00:40:04]
and it's just like to me that
[00:40:06]
I'm very uncomfortable in that
[00:40:08]
state of partial completeness
[00:40:10]
because I know that
[00:40:12]
there are risks
[00:40:14]
what if the pieces don't fit together?
[00:40:16]
There are costs to fitting the pieces together later
[00:40:18]
just losing
[00:40:20]
context. I may be building
[00:40:22]
things that I don't need
[00:40:24]
I may not be building things that
[00:40:26]
I do need. To me it's just
[00:40:28]
I'm very uncomfortable
[00:40:30]
if I'm spending a long time
[00:40:32]
building things that can't go to production
[00:40:34]
for a long time. I don't like
[00:40:36]
that feeling. I like to just be able to say
[00:40:38]
this is done, people can
[00:40:40]
use this, it was a simple thing, we can build
[00:40:42]
on top of it
[00:40:44]
I mean another type of
[00:40:46]
horizontal slicing
[00:40:48]
would be just writing
[00:40:50]
like I'm going to write a function, I think
[00:40:52]
I'm going to need this for this feature so I'm just going to
[00:40:54]
go ahead and write this code
[00:40:56]
Because you're not connecting it to
[00:40:58]
whatever is going to use it
[00:41:00]
or you're not invoking it
[00:41:02]
where you need it to
[00:41:04]
I'm going to go write
[00:41:06]
an internationalization system
[00:41:08]
and write all these
[00:41:10]
I'm going to get all these translations and things
[00:41:12]
and when I'm done building
[00:41:14]
that, then I'm going to integrate
[00:41:16]
it into the code. It's like well
[00:41:18]
wait, but how is it
[00:41:20]
going to be the right design for the code
[00:41:22]
that we have? How do you know that unless you
[00:41:24]
use it? So start
[00:41:26]
it's this mindset of
[00:41:28]
just in case versus
[00:41:30]
just in time. Build it just in time
[00:41:32]
and also like using
[00:41:34]
it as soon as possible. In fact
[00:41:36]
to me, the best
[00:41:38]
time to use it is before
[00:41:40]
it exists. Like
[00:41:42]
wishing something into
[00:41:44]
existence. Some IDEs have
[00:41:46]
create from usage
[00:41:48]
I love using create from usage
[00:41:50]
Do a test case
[00:41:52]
Write your test, red green
[00:41:54]
refactor, you write the thing you
[00:41:56]
wish it would do. One simple
[00:41:58]
example of that
[00:42:00]
I expect this function call
[00:42:02]
to give me this result. Error
[00:42:04]
this function doesn't exist
[00:42:06]
create from usage, error
[00:42:08]
through an exception
[00:42:10]
debug.todo called from this thing
[00:42:12]
fill in the thing with the
[00:42:14]
literal value. So it's
[00:42:16]
this process of like
[00:42:18]
pulling it in
[00:42:20]
in Lean they call this push
[00:42:22]
versus pull. Push being I think
[00:42:24]
I'm going to need this. So I'm going to
[00:42:26]
set all these things up that I think I'm going to
[00:42:28]
need later and pull being
[00:42:30]
hey once you need something, then you
[00:42:32]
grab it. So like in
[00:42:34]
the origins of this concept in
[00:42:36]
Lean or in manufacturing, car
[00:42:38]
manufacturing. So in a
[00:42:40]
car manufacturing scenario
[00:42:42]
they'll literally have
[00:42:44]
like boxes
[00:42:46]
with door handles that
[00:42:48]
you know when a box
[00:42:50]
becomes empty, it just
[00:42:52]
that triggers a new shipment. So you
[00:42:54]
you don't forecast how many
[00:42:56]
door handles you need. You
[00:42:58]
get an empty box and then you ship
[00:43:00]
them. Now Toyota and these
[00:43:02]
Japanese manufacturers that
[00:43:04]
pioneered Lean
[00:43:06]
concepts needed to actually
[00:43:08]
work with their suppliers
[00:43:10]
because if their suppliers
[00:43:12]
weren't operating in
[00:43:14]
a Lean way, they would often go in and
[00:43:16]
literally consult with their suppliers
[00:43:18]
the door
[00:43:20]
handle manufacturer to make
[00:43:22]
sure that they could operate in a
[00:43:24]
more Lean way. Meaning instead of saying
[00:43:26]
we're just building door handles
[00:43:28]
so just make them as fast as you possibly
[00:43:30]
can, instead saying
[00:43:32]
how short can we make it between getting
[00:43:34]
an order and fulfilling that order
[00:43:36]
and they would work
[00:43:38]
with their suppliers and make
[00:43:40]
sure that process was as streamlined as possible
[00:43:42]
so working
[00:43:44]
in this way, it
[00:43:46]
requires changes along
[00:43:48]
the way. Like we hinted at
[00:43:50]
it might require you to
[00:43:52]
have a conversation with your design
[00:43:54]
team about hey, maybe
[00:43:56]
can we try to
[00:43:58]
focus on the features we're building
[00:44:00]
so we don't end up
[00:44:02]
having to implement all these things
[00:44:04]
in our front end
[00:44:06]
for our design system that we don't yet need.
[00:44:08]
Can we focus on what are we
[00:44:10]
building this week?
[00:44:12]
I'll sit down with you and talk
[00:44:14]
about these things and talk about
[00:44:16]
maybe some issues with the design that
[00:44:18]
I don't know if I can really implement
[00:44:20]
it the way you designed it here. Can we
[00:44:22]
talk through alternatives? Because
[00:44:24]
if they just go and
[00:44:26]
design a hundred screens
[00:44:28]
maybe there's an issue in them
[00:44:30]
and you didn't get the chance to talk about
[00:44:32]
them until they had gone through all these
[00:44:34]
meetings with product people and
[00:44:36]
talked about the perfect design and now they throw
[00:44:38]
it your way and you're like oh no, that doesn't work.
[00:44:40]
So it's creating waste.
[00:44:42]
It requires changes throughout
[00:44:44]
the entire process. You have to look at it
[00:44:46]
holistically in order to
[00:44:48]
like, we're talking about
[00:44:50]
reducing unused code but you really
[00:44:52]
do have to make that change holistically
[00:44:54]
in your process.
[00:44:56]
I really, really like the vertical
[00:44:58]
slicing. Because as you said
[00:45:00]
if you have done a
[00:45:02]
nice slice, you can
[00:45:04]
ship it. You can merge it to master, you can
[00:45:06]
send it to users. There's nothing
[00:45:08]
that prevents you
[00:45:10]
from shipping it.
[00:45:12]
And from marking that
[00:45:14]
whole section of the code base as done.
[00:45:16]
You might want to improve it.
[00:45:18]
You might want to add more features.
[00:45:20]
But you can ship it and
[00:45:22]
that means you can avoid having a
[00:45:24]
very long-standing
[00:45:26]
branch in your
[00:45:28]
git repo which
[00:45:30]
creates git conflicts
[00:45:32]
which is painful to everyone.
[00:45:34]
I'm sure we've seen that.
[00:45:36]
We've all seen that.
[00:45:38]
When you try to have a branch that is
[00:45:40]
two months old and like, yeah...
[00:45:42]
It creates problems.
[00:45:44]
But yeah, so vertical slicing
[00:45:46]
if you can go for that
[00:45:48]
that sounds great.
[00:45:50]
Horizontal slicing, I think
[00:45:52]
you can make it work or at least I feel
[00:45:54]
like you can do that
[00:45:56]
best when
[00:45:58]
trying to do a vertical slice.
[00:46:00]
So when you do a vertical slice
[00:46:02]
let's say you need a front end and you need
[00:46:04]
a back end. Well, you can do
[00:46:06]
the front end
[00:46:08]
as a horizontal slice
[00:46:10]
and the back end as a horizontal slice
[00:46:12]
of that vertical slice.
[00:46:14]
And that's like
[00:46:16]
if you don't want to ship that code because
[00:46:18]
it's not ready yet, you can
[00:46:20]
use other techniques like
[00:46:22]
feature flags.
[00:46:24]
To me, feature flags are
[00:46:26]
an essential part of
[00:46:28]
shipping small vertical slices.
[00:46:30]
If you want to
[00:46:32]
actually deploy
[00:46:34]
code, because it is
[00:46:36]
a product and a
[00:46:38]
management decision
[00:46:40]
to release something to go
[00:46:42]
live in production.
[00:46:44]
Sometimes people talk about
[00:46:46]
deployment versus release.
[00:46:48]
It's a product and a
[00:46:50]
management decision to release something
[00:46:52]
but deploying is a technical decision.
[00:46:54]
Right. So for instance, we want
[00:46:56]
v2 of our new
[00:46:58]
product to be released
[00:47:00]
then.
[00:47:02]
But we want to be...
[00:47:04]
Yeah, it's somewhat
[00:47:06]
similar but we want it
[00:47:08]
to be ready. We want to test it
[00:47:10]
on some computers or
[00:47:12]
some servers maybe. But we
[00:47:14]
want to only make it available to
[00:47:16]
some of the users at this time.
[00:47:18]
We have a big conference
[00:47:20]
and we want to go
[00:47:22]
live with this new feature on the day of the
[00:47:24]
conference. But do you want
[00:47:26]
to hit the deploy button
[00:47:28]
on the day of the conference
[00:47:30]
and make sure everything is ready and fix any
[00:47:32]
bugs that come up? Or do you want
[00:47:34]
to ship it with a feature flag and
[00:47:36]
people are not doing
[00:47:38]
merge conflicts the day of
[00:47:40]
the conference when you hit deploy
[00:47:42]
because the code has been sitting around on a branch
[00:47:44]
and not shipped
[00:47:46]
to production? Or do you
[00:47:48]
want to have people working
[00:47:50]
with the code change that
[00:47:52]
was shipped to the production
[00:47:54]
system
[00:47:56]
so you don't have any
[00:47:58]
merge conflicts but it's behind
[00:48:00]
a feature flag that's switched off except
[00:48:02]
for admin users or whatever.
[00:48:04]
So
[00:48:06]
this is one of the core practices
[00:48:08]
for working this way.
[00:48:10]
But you ship it
[00:48:12]
as soon as you possibly
[00:48:14]
can.
[00:48:16]
You're
[00:48:18]
making a new
[00:48:20]
settings page
[00:48:22]
and you
[00:48:24]
ship it right away. You make the settings
[00:48:26]
page, boom, it's live.
[00:48:28]
Does it do anything? Well, it doesn't matter
[00:48:30]
because it's only accessible if you have this feature
[00:48:32]
flag on. So it's safe to ship.
[00:48:34]
So it requires that mindset.
[00:48:36]
Even if it's absolutely empty.
[00:48:38]
Right. Now you would
[00:48:40]
probably want to have
[00:48:42]
something meaningful
[00:48:44]
of like, what's
[00:48:46]
the simplest setting?
[00:48:48]
This is for changing your
[00:48:50]
username. Okay, well, can
[00:48:52]
we ship it without any
[00:48:54]
validations but have that
[00:48:56]
without any
[00:48:58]
UI validations, only back
[00:49:00]
end validations, right? So that's like a shippable
[00:49:02]
thing that someone can use
[00:49:04]
and test out and
[00:49:06]
we can loop back around to like fancy
[00:49:08]
UI for the front end
[00:49:10]
validations later, for example.
[00:49:12]
So this is all like
[00:49:14]
the concept of trunk-based development
[00:49:16]
and continuous delivery and
[00:49:18]
it's, I mean, it's a lot.
[00:49:20]
And it does require the whole
[00:49:22]
organization to sort of be on board
[00:49:24]
with this process.
[00:49:26]
Yeah.
[00:49:28]
Especially just the fact that
[00:49:30]
you want to have like a continuous
[00:49:32]
deployment. That often
[00:49:34]
comes with that approach,
[00:49:36]
right, where you merge something to master.
[00:49:38]
Well, and everyone can merge
[00:49:40]
something to master, even
[00:49:42]
very tiny things. Sometimes
[00:49:44]
without supervision because you're pairing
[00:49:46]
with other people. And then
[00:49:48]
anything that gets shipped to master gets
[00:49:50]
continually deployed
[00:49:52]
to production.
[00:49:54]
And yeah, in plenty of organizations
[00:49:56]
if that is not automated,
[00:49:58]
that's not going to work
[00:50:00]
out. Or it's going to be
[00:50:02]
subpar, I'm guessing.
[00:50:04]
Absolutely. And so you
[00:50:06]
have to be committed to
[00:50:08]
making all these changes that enable
[00:50:10]
you to work in this way. So I definitely
[00:50:12]
don't say it lightly. It's a
[00:50:14]
huge mindset shift.
[00:50:16]
But I think this core
[00:50:18]
mindset shift of seeing the waste
[00:50:20]
in merge
[00:50:22]
conflicts, seeing the inefficiency
[00:50:24]
in these ways and
[00:50:26]
realizing that actually if I
[00:50:28]
can ship one small thing, it's not
[00:50:30]
inefficient. It's actually more efficient.
[00:50:32]
I can think of this one small
[00:50:34]
slice of the functionality and
[00:50:36]
get it tested and
[00:50:38]
working. And then
[00:50:40]
trusting yourself to loop back around
[00:50:42]
and add the additional features
[00:50:44]
later. And maybe you don't even need the additional features.
[00:50:46]
So it gives the engineers
[00:50:48]
and the product team the ability
[00:50:50]
to do that 80-20
[00:50:52]
and say, you know what, this actually is good enough
[00:50:54]
for now. Let's prioritize another feature
[00:50:56]
first. So seeing the
[00:50:58]
efficiency of that workflow
[00:51:00]
I think is a really good first step.
[00:51:02]
When you say have an
[00:51:04]
eye for waste, you basically see
[00:51:06]
you basically mean
[00:51:08]
trying to find all the
[00:51:10]
wasteful processes
[00:51:12]
or where you lose time,
[00:51:14]
right? So you mentioned
[00:51:16]
handling
[00:51:18]
merge conflicts, which makes
[00:51:20]
a lot of sense because
[00:51:22]
they can be painful.
[00:51:24]
One of the things you
[00:51:26]
need for this is you need to have a good
[00:51:28]
test suite. You need to have
[00:51:30]
a good compiler, you need
[00:51:32]
to have linter that checks that
[00:51:34]
everything that goes into master
[00:51:36]
works as expected. But you can also
[00:51:38]
argue, I guess, and I would
[00:51:40]
like your take on this,
[00:51:42]
is that if
[00:51:44]
Elm Review tells you, oh,
[00:51:46]
this can't be shipped to production
[00:51:48]
because you have an unused function,
[00:51:50]
isn't that kind of a waste
[00:51:52]
in a way?
[00:51:54]
Right, well, that's why I say
[00:51:56]
eyes for waste is
[00:51:58]
it's understanding
[00:52:00]
the types of waste that come
[00:52:02]
from working in this
[00:52:04]
big batch way. Is it just
[00:52:06]
a matter of trade-offs? Like we want
[00:52:08]
to have a
[00:52:10]
high quality and we're going to
[00:52:12]
we're willing to pay this
[00:52:14]
price in terms of
[00:52:16]
slowing you down
[00:52:18]
to be able to have that high quality of code.
[00:52:20]
We don't
[00:52:22]
want you to be able to ship something
[00:52:24]
where a test has gone red
[00:52:26]
because that's going to impact the
[00:52:28]
behavior of the code. And we're willing to
[00:52:30]
slow you down because of that.
[00:52:32]
It's a very good question.
[00:52:34]
Let's say you're making
[00:52:38]
let's say you have a factory
[00:52:40]
that makes rubber bands.
[00:52:42]
This single size
[00:52:44]
of rubber band, there's like a constant
[00:52:46]
demand for it. We can forecast
[00:52:48]
the demand for rubber bands
[00:52:50]
each year. It doesn't change that much.
[00:52:52]
You mean the demand for
[00:52:54]
rubber bands is constant, not elastic?
[00:52:56]
It's not elastic, exactly.
[00:52:58]
Okay.
[00:53:00]
So, you don't want to
[00:53:02]
optimize for flexibility
[00:53:04]
although perhaps a rubber band
[00:53:06]
manufacturer would want to
[00:53:08]
optimize for flexibility. I'm not sure.
[00:53:10]
To some extent.
[00:53:12]
To...
[00:53:14]
It's baked
[00:53:16]
into their process.
[00:53:18]
Yeah, it has to be
[00:53:20]
at some point or another.
[00:53:22]
So, it might be
[00:53:24]
a bit of a stretch, but
[00:53:26]
the rubber band
[00:53:28]
manufacturer, let's just
[00:53:30]
imagine they have a
[00:53:32]
pretty good grasp
[00:53:34]
on how much demand there is.
[00:53:36]
They know how much they want to produce per year.
[00:53:38]
They know their process.
[00:53:40]
They're not trying to adapt it every day.
[00:53:42]
They're not trying to create
[00:53:44]
the next electric car
[00:53:46]
breakthrough that's going
[00:53:48]
to transform the industry.
[00:53:50]
They're not trying to create an innovative
[00:53:52]
competitive software
[00:53:54]
product that is going to stay ahead
[00:53:56]
of the competition and be the
[00:53:58]
best in class. They're trying to create
[00:54:00]
rubber bands. Yeah, exactly.
[00:54:02]
They're not doing those things, right? Yeah, yeah, okay.
[00:54:04]
Okay, so for this rubber band
[00:54:06]
manufacturer, maybe
[00:54:08]
they're okay with optimizing
[00:54:10]
for horizontal slicing.
[00:54:12]
Maybe they know exactly how many they're going
[00:54:14]
to create, so they don't need a flexible
[00:54:16]
process. They don't need an adaptable
[00:54:18]
process. So, to me,
[00:54:20]
that's the question.
[00:54:22]
How adaptable do you want to be?
[00:54:24]
Maybe if you are a
[00:54:26]
web agency
[00:54:28]
creating photography
[00:54:30]
websites for professional
[00:54:32]
photographers, and they can
[00:54:34]
have a portal to share things
[00:54:36]
with their clients or whatever. It's like
[00:54:38]
you stamp it up. You're making wedding
[00:54:40]
websites. You're making
[00:54:42]
mom and pop
[00:54:44]
restaurant websites. Okay.
[00:54:46]
Maybe in that case
[00:54:48]
you know exactly what the process
[00:54:50]
is and you're just repeating it every time.
[00:54:52]
So, to
[00:54:54]
me, this lean eyes for
[00:54:56]
waste,
[00:54:58]
to me, it's not so much a
[00:55:00]
trade-off of the kinds of waste
[00:55:02]
of doing everything big batch
[00:55:04]
and doing everything in small lean
[00:55:06]
batches. It's a question
[00:55:08]
of optimizing for flexibility or not.
[00:55:10]
So, eyes for
[00:55:12]
waste in lean is understanding
[00:55:14]
that you're making yourself
[00:55:16]
less flexible. And if you want to
[00:55:18]
optimize for something other than flexibility,
[00:55:20]
then you might make a different
[00:55:22]
set of choices. That's how I see it.
[00:55:24]
Am I correct or incorrect to say that
[00:55:26]
lean is a process that
[00:55:28]
is optimized for incoming
[00:55:30]
changes? Yes.
[00:55:32]
Okay. I would 100%
[00:55:34]
agree with that. Lean, you don't want
[00:55:36]
a lot of unsold
[00:55:38]
cars. You want
[00:55:40]
a lot of cars that
[00:55:42]
a lot is in like a parking lot, like a
[00:55:44]
car showroom
[00:55:46]
lot that has
[00:55:48]
cars that are
[00:55:50]
getting sold. And then it's like,
[00:55:52]
oh, they're selling really well. Great. Let's
[00:55:54]
make some more. Let's ramp up
[00:55:56]
production on that instead of
[00:55:58]
we thought these cars were going to
[00:56:00]
sell really well, but that's waste.
[00:56:02]
That's like a bunch of cars that didn't sell.
[00:56:04]
Lean is all about
[00:56:06]
that's the origins of lean.
[00:56:08]
But these principles very much apply.
[00:56:10]
And it's all about looking
[00:56:12]
at how you shorten the
[00:56:14]
time from starting
[00:56:16]
to finishing something and actually
[00:56:18]
finishing, not partially finishing.
[00:56:20]
It's a holistic
[00:56:22]
concept of done.
[00:56:24]
All right. Now, I will mention
[00:56:26]
we've talked about this before.
[00:56:28]
If you want to have some code
[00:56:30]
that is partially done,
[00:56:32]
another place where
[00:56:34]
partially done
[00:56:36]
code can happen is prototyping.
[00:56:38]
I think that doing small
[00:56:40]
spikes, small experiments
[00:56:42]
is a great idea, right?
[00:56:44]
But the purpose
[00:56:46]
of a spike
[00:56:48]
is to experiment in order to learn
[00:56:50]
something, not to
[00:56:52]
have some deliverable code.
[00:56:54]
So you would never, or
[00:56:56]
almost never, include that into
[00:56:58]
production code. So you would never merge that into
[00:57:00]
master, even not behind a feature
[00:57:02]
flag, or maybe behind a feature flag?
[00:57:04]
I would think of it as
[00:57:06]
you throw it away at the end.
[00:57:08]
And the purpose is
[00:57:10]
as quickly as we can get to that
[00:57:12]
learning goal, we're going to optimize for
[00:57:14]
that all the way. I guess you could
[00:57:16]
have a spike where you're
[00:57:18]
trying a test on some production code
[00:57:20]
for performance, and you say, hey, if we
[00:57:22]
do this performance change,
[00:57:24]
is it going to
[00:57:26]
be faster? And maybe
[00:57:28]
it's, oh, you know what?
[00:57:30]
I actually experimented with a bunch of things.
[00:57:32]
I made this one change, and
[00:57:34]
actually it's good, so we can merge this.
[00:57:36]
But the general idea,
[00:57:38]
you're optimizing for learning.
[00:57:40]
That's the gist of it.
[00:57:42]
Or you can ship something, like the
[00:57:44]
new settings page, to one of your customers
[00:57:46]
that really wants this
[00:57:48]
new thing, and
[00:57:50]
you send it to production,
[00:57:52]
and
[00:57:54]
they validate it, or they say,
[00:57:56]
no, there's something wrong with this, it's not what we
[00:57:58]
wanted, actually.
[00:58:00]
And then you can delete that, and then
[00:58:02]
you do it properly. Absolutely, yeah.
[00:58:04]
Right. And I wouldn't call that a spike.
[00:58:06]
I would just call that
[00:58:08]
a partial rollout. But yeah,
[00:58:10]
absolutely. Why would you call
[00:58:12]
that a spike? Because you're
[00:58:14]
merging it? It's more
[00:58:16]
like A-B testing,
[00:58:18]
or user testing,
[00:58:20]
or... I mean, of course
[00:58:22]
you could do
[00:58:24]
user
[00:58:26]
tests as well, without
[00:58:28]
rolling out a feature change there.
[00:58:30]
To me, a spike is more just like,
[00:58:32]
we're not necessarily trying
[00:58:34]
to tweak the product
[00:58:36]
and learn how users
[00:58:38]
respond to it. I just
[00:58:40]
categorize that under more A-B
[00:58:42]
testing type of stuff, I guess.
[00:58:44]
Yeah, then it's basically the same
[00:58:46]
idea, but then put different words on it.
[00:58:48]
Yeah.
[00:58:50]
Yeah. But it's definitely
[00:58:52]
challenging stuff,
[00:58:54]
and there's also, like, in TDD,
[00:58:56]
there's a whole different
[00:58:58]
set of schools of thought between
[00:59:00]
outside-in TDD and inside-out,
[00:59:02]
where outside-in
[00:59:04]
is more of a pull-based
[00:59:06]
model, and inside-out is kind of more of a
[00:59:08]
push-based model. And people
[00:59:10]
have different opinions on this, but
[00:59:12]
inside-out TDD is
[00:59:14]
more the traditional standard
[00:59:16]
approach we're used to.
[00:59:18]
So if you're, you know,
[00:59:20]
if you're building out some tests,
[00:59:22]
and maybe you're,
[00:59:24]
you know, maybe you're not using
[00:59:26]
them yet, whereas inside-out would be more,
[00:59:28]
okay, I'm writing
[00:59:30]
an end-to-end test. I'm
[00:59:32]
using this thing. Now
[00:59:34]
I need to drop into a more
[00:59:36]
low-level unit test for
[00:59:38]
all of these corner cases.
[00:59:40]
So now I'm gonna start
[00:59:42]
writing these smaller unit
[00:59:44]
tests, but I'm gonna start with
[00:59:46]
the top-level
[00:59:48]
thing. But yeah, I think, I mean,
[00:59:50]
if you're using
[00:59:52]
TDD, that in itself is
[00:59:54]
really gonna help you avoid
[00:59:56]
unused code quite a lot. I mean,
[00:59:58]
this, you're talking about this
[01:00:00]
rule you're building, this
[01:00:02]
Elm Review rule that lets you detect
[01:00:04]
something that is only used in test
[01:00:06]
code. So, and
[01:00:08]
that is definitely, like,
[01:00:10]
yeah, if something is only used in test code,
[01:00:12]
then it's like, is it really used
[01:00:14]
code? Not really, right? So...
[01:00:16]
Yeah, in this case, like,
[01:00:18]
do you want to maintain it or probably
[01:00:20]
not? Right, exactly. Yeah, you probably want to know
[01:00:22]
about it. You probably want to know, hey, there's this thing that's
[01:00:24]
being tested, but it's not being used anywhere else.
[01:00:26]
I know that a lot
[01:00:28]
of people have written tests
[01:00:30]
for functions that they wanted to keep
[01:00:32]
just so that Elm Review doesn't report
[01:00:34]
them, which is
[01:00:36]
in a way a good thing because they're
[01:00:38]
running tests. Yeah.
[01:00:40]
But if that's
[01:00:42]
just a way to
[01:00:44]
escape Elm Review, then just
[01:00:46]
know that I'm coming for you.
[01:00:48]
Whatever means
[01:00:50]
you're trying to come up with
[01:00:52]
where Elm Review doesn't
[01:00:54]
detect unused code, I'm
[01:00:56]
coming for you.
[01:00:58]
Don't rely on it
[01:01:00]
for a long time. I'm gonna
[01:01:02]
try to improve it in any way,
[01:01:04]
shape or possible.
[01:01:06]
So, for instance,
[01:01:08]
right now you can have
[01:01:10]
additional record fields
[01:01:12]
in your records
[01:01:14]
because Elm Review is not
[01:01:16]
collecting them or reporting them.
[01:01:18]
But at some point, I
[01:01:20]
know that's gonna come at some point.
[01:01:22]
And that's gonna
[01:01:24]
create so many snowball effects, or I hope
[01:01:26]
so at least. So Elm Review
[01:01:28]
definitely, when
[01:01:30]
you came up with the
[01:01:32]
no unused custom type constructor
[01:01:34]
rule, that
[01:01:36]
definitely caught a lot
[01:01:38]
of things in my code that I was like, wow.
[01:01:40]
And often it's, I mean, sometimes
[01:01:42]
it's a premature thing that
[01:01:44]
I didn't even realize I was doing.
[01:01:46]
That I'm just creating a variant
[01:01:48]
and I'm modeling
[01:01:50]
my, I'm domain modeling.
[01:01:52]
And I do kind of like
[01:01:54]
this process, but
[01:01:56]
sometimes I'll even comment out,
[01:01:58]
like sometimes I'll do the domain modeling,
[01:02:00]
I'll write a custom type, and then I'll
[01:02:02]
comment out some of the ones that I'm not
[01:02:04]
using. And I think
[01:02:06]
that's okay.
[01:02:08]
It's not really tying me up too
[01:02:10]
much. And I usually try to
[01:02:12]
tidy up those commented
[01:02:14]
unused variants
[01:02:16]
as I'm
[01:02:18]
committing. If I realize
[01:02:20]
that I don't need them anymore.
[01:02:22]
But I keep it almost
[01:02:24]
like a checklist for myself. And I kind of
[01:02:26]
like that process.
[01:02:28]
I think you're writing a to-do list for you.
[01:02:30]
Except you're writing it in your
[01:02:32]
code. And I think that's fine
[01:02:34]
as long as you have,
[01:02:36]
as long as you're sure that you're going
[01:02:38]
to go back to that
[01:02:40]
and clean things up when everything's
[01:02:42]
done or everything works as expected.
[01:02:44]
Or implement those things,
[01:02:46]
obviously. Right. You know, the
[01:02:48]
other way you could do that is just
[01:02:50]
write your custom type and start
[01:02:52]
writing all your cases. But I think
[01:02:54]
it's a brilliant way to write
[01:02:56]
code that you say, I'm just going to have
[01:02:58]
this one case for now. And
[01:03:00]
I'm going to do a case expression
[01:03:02]
that only has a single
[01:03:04]
pattern in it to start.
[01:03:06]
And then I'm going to write
[01:03:08]
a failing test. And I'm going
[01:03:10]
to need a new variant to implement
[01:03:12]
that and get it green.
[01:03:14]
And then, guess what?
[01:03:16]
The Elm compiler is going to tell you all the places you
[01:03:18]
need to go handle. Which is an amazing
[01:03:20]
workflow. But I think starting it out
[01:03:22]
as a custom type is
[01:03:24]
a great device.
[01:03:26]
As opposed to just a raw
[01:03:28]
primitive type or a record. Because it's like, well, I know.
[01:03:30]
It would be nice if there were automated
[01:03:32]
tools for like, taking
[01:03:34]
a record type you have somewhere and then
[01:03:36]
saying, I actually want this record to
[01:03:38]
be wrapped in a custom type now. That would be super
[01:03:40]
cool. Yeah, that'd be really
[01:03:42]
cool. Yeah. And doable
[01:03:44]
as well. Yeah.
[01:03:46]
Automated refactoring tools really
[01:03:48]
do... I mean, we're talking about
[01:03:50]
Elm review rules.
[01:03:52]
And automated refactoring
[01:03:54]
tools, automated testing tools, all these
[01:03:56]
things are really essential
[01:03:58]
for this type of process, I think.
[01:04:00]
It allows you to be way more flexible
[01:04:02]
in the way you approach your code workflow because
[01:04:04]
the cost of change is lower.
[01:04:06]
Elm also makes the cost of change lower because
[01:04:08]
it's very predictable, maintainable code.
[01:04:10]
Yeah. Anything that helps you
[01:04:12]
make changes to your code
[01:04:14]
in predictable ways is always
[01:04:16]
an improvement. Exactly. It's optimizing
[01:04:18]
for flexibility, right? So, in a
[01:04:20]
way, Elm is very good for helping you optimize
[01:04:22]
for flexibility as a language.
[01:04:24]
So, anything else people should look at
[01:04:26]
besides all of the great Elm Review
[01:04:28]
no unused rules?
[01:04:30]
I think we're good.
[01:04:32]
Just a reminder that
[01:04:34]
if Elm Review is blocking you from
[01:04:36]
doing what you really want,
[01:04:38]
you can always use Elm Review suppress
[01:04:40]
and then communicate
[01:04:42]
with your teammates to know whether that
[01:04:44]
suppression was okay or not.
[01:04:46]
And then making sure
[01:04:48]
yourself, like in your
[01:04:50]
internal process or team process,
[01:04:52]
go through the suppressed errors
[01:04:54]
because that is now technical
[01:04:56]
debt that has been somewhat
[01:04:58]
identified. But it is okay
[01:05:00]
to have some technical debt
[01:05:02]
as long as you remove it
[01:05:04]
later in the future. So, that is
[01:05:06]
also one way you can do
[01:05:08]
things. But if you can avoid
[01:05:10]
having unused code
[01:05:12]
in the first place using whatever
[01:05:14]
we just... whatever technique
[01:05:16]
we just mentioned during this
[01:05:18]
episode, then that's probably
[01:05:20]
a better solution.
[01:05:22]
And as we've mentioned before,
[01:05:24]
if you are able to remove
[01:05:26]
all these suppressed cases, then
[01:05:28]
that's a whole new guarantee you have for your codebase.
[01:05:30]
Including, you know, a guarantee
[01:05:32]
that you don't have unused functions.
[01:05:34]
That's kind of cool. You're browsing through your codebase
[01:05:36]
and you know if a function
[01:05:38]
is being
[01:05:40]
declared, it's used.
[01:05:42]
Thankfully, even if you suppress
[01:05:44]
that, like
[01:05:46]
just because Elm has that code elimination
[01:05:48]
or live code inclusion,
[01:05:50]
the cost of keeping that code
[01:05:52]
is pretty much only
[01:05:54]
in terms of maintenance,
[01:05:56]
not bundle size.
[01:05:58]
Well, for unused functions at least,
[01:06:00]
for unused custom types, there is an impact.
[01:06:02]
Right. Or for
[01:06:04]
dead code paths.
[01:06:06]
Dead code paths, yeah. Also,
[01:06:08]
so, run ElmReview,
[01:06:10]
the unused package, the simplified package,
[01:06:12]
and all the other
[01:06:14]
ones that I made, I'm sure they're all great
[01:06:16]
and applicable everywhere.
[01:06:18]
Not biased.
[01:06:20]
Share your lines of
[01:06:22]
deleted code screenshots from your
[01:06:24]
pull requests and let us know how
[01:06:26]
it goes. Yep. Always
[01:06:28]
looking forward to hearing more about those.
[01:06:30]
And Jeroen, until
[01:06:32]
next time. Until next time.