spotifyovercastrssapple-podcasts

Avoiding Unused Code

We discuss how to avoid unused Elm code, why it matters, and what leads to unused code in the first place.
August 14, 2023
#88

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.