spotifyovercastrssapple-podcasts

Writing Great Docs

We discuss why the baseline for Elm docs is so high, how to navigate docs as a user, and how to make your own docs great.
June 19, 2023
#84

Transcript

[00:00:00]
Hello Jeroen.
[00:00:02]
Hey, what's up Doc?
[00:00:04]
Oh, you're trying to beat me at my own game, are we?
[00:00:10]
Yes, I found a pun.
[00:00:13]
And I'm going with it.
[00:00:15]
Even if I have to destroy the holy intro that we have.
[00:00:20]
Wow, breaking with the format.
[00:00:23]
Well, I will admit, I was trying to think of a good one,
[00:00:26]
but I was having a little bit of writer's block, so...
[00:00:29]
I'm gonna say it's funny, but I don't think I get it.
[00:00:34]
But it's funny, Dillon. It's very funny. Please continue doing that.
[00:00:38]
Maybe it's just me. When I think of documentation,
[00:00:41]
the first thing that comes to mind is writer's block,
[00:00:44]
because I am sitting there staring at a blank page,
[00:00:47]
and it is very painful.
[00:00:49]
But, Jeroen, as always, we endure that pain for our dear users.
[00:00:55]
Definitely true, yeah.
[00:00:58]
We will suffer through writing JavaScript,
[00:01:01]
we will suffer through writing English words,
[00:01:04]
all in the name of our users.
[00:01:06]
And it's a very noble view of, I guess, all of us then?
[00:01:11]
I was not trying to praise myself, but I guess I am.
[00:01:15]
I don't know about you, but I do find it way more difficult
[00:01:20]
than writing the code.
[00:01:23]
Yeah, definitely agree.
[00:01:25]
So maybe before we delve into that, what is our topic today?
[00:01:28]
What is our topic? I'm gonna say it is writing great docs.
[00:01:33]
Not just good docs, because, as Evan says in the Elm Philosophy tweet,
[00:01:38]
it's not done until the docs are great.
[00:01:41]
And I do love that as a sort of foundational principle in Elm.
[00:01:45]
And, you know, I mean, when you write an Elm package,
[00:01:49]
the docs are already pretty good as a starting point,
[00:01:52]
because you are required to have, you know, types for all of your exposed APIs,
[00:01:59]
and it comes with already a really good, easy-to-navigate set of documentation
[00:02:04]
for your package.
[00:02:05]
Like, honestly, better than almost any other programming language I've seen.
[00:02:10]
But in addition to that, we go above and beyond,
[00:02:13]
and we try to make it a really good flow through reading that
[00:02:18]
and getting up and running with our package.
[00:02:20]
I thought it would be fun to talk about, like, what do make docs great?
[00:02:24]
What's the process for great docs?
[00:02:26]
What should package authors be thinking about for making their docs great?
[00:02:30]
How should users use that information to navigate docs?
[00:02:34]
And, you know, maybe whether those things are relevant
[00:02:36]
for documenting an application.
[00:02:39]
I think one of the reasons why we tend to have great docs in Elm
[00:02:43]
is because all the tools and packages that we enjoy using
[00:02:49]
have great docs.
[00:02:51]
So I think it's kind of a culture thing.
[00:02:53]
Like, in the Elm community, whenever we release something,
[00:02:57]
we write great docs.
[00:02:59]
And it's kind of the same as, like, oh, well,
[00:03:02]
every time we try to make something, we want it to be type-safe.
[00:03:07]
That's just the culture that we have.
[00:03:09]
And it's one that has been with Elm for a long time.
[00:03:14]
I don't know how long, but at least before my time with Elm.
[00:03:18]
And therefore, the expectation is that every time you write docs,
[00:03:23]
they have to be great.
[00:03:25]
And that culture at the start is very important
[00:03:29]
because now it's set in stone almost.
[00:03:31]
And whenever I see packages that are not great quality-wise or doc-wise,
[00:03:37]
it's usually by someone who has just learned Elm
[00:03:41]
and was just introduced to Elm
[00:03:43]
and doesn't have the expanded experience with Elm.
[00:03:47]
And that's fine, I guess.
[00:03:49]
They're going to learn at some point.
[00:03:51]
Interesting.
[00:03:52]
So when you say that you've grown accustomed to Elm packages with great docs,
[00:04:00]
can you dig in a little bit to what that means to you?
[00:04:03]
Like, as a consumer of documentation, what makes them great?
[00:04:07]
What are the things you notice about those packages?
[00:04:10]
Well, maybe let's start with the first thing that is obvious
[00:04:14]
but also quite not obvious.
[00:04:16]
The whole API of the package is documented.
[00:04:21]
If I remember my NPM days or JavaScript days,
[00:04:25]
you had a package and the documentation for that package was the readme.
[00:04:31]
And maybe like an additional website, but it's usually like the readme
[00:04:34]
and everything is in readme.
[00:04:36]
More on that later, I think.
[00:04:39]
But the API that would be in the readme,
[00:04:42]
sometimes it's just like an example like, oh, this is what you can do with this package.
[00:04:47]
You can do this, and they show a simplified example
[00:04:50]
because it's annoying to write a lot of documentation.
[00:04:55]
And then that's it.
[00:04:57]
Or they write a lot of options,
[00:05:01]
but they don't write all of the ways that you can use this package,
[00:05:06]
all the ways that are intended, nor the ones that are unintended,
[00:05:11]
which makes sense that they're unintended.
[00:05:14]
But I've seen a lot of packages where you would open an issue saying,
[00:05:18]
oh, I would love to be able to do this.
[00:05:20]
And they would answer, oh, well, you can import this submodule of the package,
[00:05:26]
and then you can do that.
[00:05:28]
But that's not documented.
[00:05:30]
And now, usually you would say, oh, now I'm using internals,
[00:05:36]
which is not good, and in practice, it's not good.
[00:05:39]
So yeah, the fact that we have to document everything in the API,
[00:05:44]
or just that they're shown in the package documentation,
[00:05:48]
is already a great point, I think, in the end.
[00:05:51]
Yeah, that definitely resonates with me.
[00:05:53]
I can think of so many times when I've been trying to figure out
[00:05:56]
how to do something with an npm package,
[00:05:59]
and I'm searching through and often end up digging through obscure issues
[00:06:06]
that I have to Google for and find some niche use of it that isn't documented
[00:06:12]
or isn't documented in a clear place.
[00:06:16]
Or I have to search through the source code and see what it's checking for.
[00:06:21]
If this object property exists, then do this.
[00:06:24]
If it doesn't, then do that.
[00:06:26]
So it's true.
[00:06:27]
By virtue of publishing an Elm package, those things are documented.
[00:06:33]
So that's the bare minimum for an Elm package.
[00:06:36]
So another part is every API is shown,
[00:06:41]
like all the custom types or the functions that are there,
[00:06:46]
all the type aliases.
[00:06:48]
But whenever you try to publish a package,
[00:06:51]
one of the things that the Elm compiler will tell you
[00:06:53]
is that some of the functions or some of the types are not documented,
[00:06:57]
and you need to.
[00:06:59]
So Elm forces you to write documentation for all those exposed APIs,
[00:07:05]
all those public APIs.
[00:07:07]
So even if you don't think you're going to write good docs for them,
[00:07:12]
you have to carefully or you have to make that decision purposefully.
[00:07:18]
But sometimes it's pretty easy to just write some documentation,
[00:07:22]
some explanation, oh, this function does this,
[00:07:25]
and then, oh, I might as well add one little example,
[00:07:30]
and now it's already very usable.
[00:07:33]
So that's like that little nudge that asks you to write some documentation,
[00:07:38]
even if it's empty, which I don't like, but we can talk about that later.
[00:07:43]
That little nudge already pushes you to write some documentation
[00:07:48]
and potentially to make it good.
[00:07:50]
So when you're consuming an Elm package,
[00:07:55]
what do those docs look like when they feel like they're really helping you?
[00:07:59]
What's your experience?
[00:08:01]
So that's one of the things I'm curious to dig into here too,
[00:08:03]
because I think in order to talk about great docs,
[00:08:07]
I think it's really good to put yourself in the user's shoes,
[00:08:11]
and we happen to be users of Elm packages
[00:08:14]
and consumers of docs for Elm packages.
[00:08:17]
So what is it, like, when we're looking at those beautiful Elm package docs
[00:08:22]
and they're not left blank and there's something written there,
[00:08:26]
what is it that makes it really good?
[00:08:29]
I think they always say, like,
[00:08:32]
this is a blazingly fast package to do something, or...
[00:08:38]
No, wait, sorry, that's NPM.
[00:08:41]
Yeah.
[00:08:42]
Sorry, I messed it up.
[00:08:44]
The logo really helps you understand what it does too.
[00:08:47]
Yeah, and the visual design and the 100 SCO score that you have.
[00:08:53]
No, yeah, so you usually want to look at a package.
[00:08:57]
The first thing that I see is the name of the package, who made it,
[00:09:00]
and then a description of what it does, like, what is the purpose of this,
[00:09:05]
or what does this package help you with,
[00:09:08]
then some examples of how to use it.
[00:09:11]
But also in some cases where you have, like,
[00:09:15]
for instance, if you have, like, a package to parse some format,
[00:09:19]
like, that's pretty obvious what it does.
[00:09:22]
So you don't have to explain it too much.
[00:09:25]
You have to explain how to use it, but not how it works under the hood
[00:09:30]
or what are the advantages of using this approach.
[00:09:34]
But whenever there are multiple alternatives to solution,
[00:09:39]
say, GraphQL packages,
[00:09:42]
what I often see is, like, the philosophy behind a package
[00:09:46]
or the trade-offs, or hopefully the trade-offs of the solution.
[00:09:52]
So I think explaining the philosophy or the trade-offs that are involved
[00:09:57]
in this solution versus other solutions,
[00:10:01]
sometimes even referencing the other solutions,
[00:10:04]
is a great thing to have in your docs.
[00:10:07]
Just saying it's blazingly fast is not necessarily helpful,
[00:10:10]
especially if all of them say that.
[00:10:13]
Right. Unless that's part of the philosophy, and it's a differentiator.
[00:10:17]
Yeah, but then you would need to say, like,
[00:10:21]
the reason why it's blazingly fast is either we try this new approach,
[00:10:26]
or there's a trade-off, like, this is simpler,
[00:10:29]
this doesn't handle all the edge cases,
[00:10:31]
but for the normal cases, it's going to be way faster.
[00:10:36]
And that's something that you would like to see.
[00:10:39]
Right. If it's a drop-in replacement for Dict, except faster,
[00:10:43]
that's the only thing that's different, then that's what you want to know.
[00:10:47]
And that's a good way to describe it.
[00:10:49]
And maybe in that case, the package can also handle the more complex approach.
[00:10:56]
And then it's just, like, having the best of both worlds, I guess.
[00:11:00]
Maybe in a somewhat convoluted way, maybe. Who knows?
[00:11:03]
Mm-hmm. Mm-hmm.
[00:11:04]
But yeah, I think I'm looking for all those.
[00:11:07]
So, description, examples, philosophy.
[00:11:11]
But yeah, description of the APIs, and how to use those,
[00:11:17]
and how to use them together through a guide or through examples.
[00:11:21]
That's the kind of things that I'm looking for.
[00:11:24]
Right. Yeah, that resonates with me as well.
[00:11:28]
I would say, when I go to open up the package documentation for an Elm package,
[00:11:34]
as you say, often there will be a few alternatives, and they have the same name.
[00:11:39]
They're all called ElmGraphQL, or they're all called, you know, ElmAnyDict,
[00:11:47]
or, you know, ElmMarkdown, or whatever.
[00:11:50]
And it's like, okay, well, so I want to know.
[00:11:53]
The first thing I'm trying to find out as fast as possible is, does this,
[00:12:00]
number one, can I use this for the problem I'm trying to solve?
[00:12:04]
Because if I can't, I don't even want to consider if I like it,
[00:12:09]
or if I like its trade-offs.
[00:12:11]
Just like, what problem can I use this to solve?
[00:12:14]
Is this a faster dict? No, this is ElmGraphQL.
[00:12:17]
Okay, well, then I'm just going to skip it.
[00:12:19]
Right. It better tell you that quickly.
[00:12:22]
And you don't have much of, I mean, I can say this from personal experience,
[00:12:28]
as a reader of docs, you do not have my attention for very long to tell me that.
[00:12:34]
And if it's like a very long-form description of things that doesn't just,
[00:12:41]
like, right at the top in a topic sentence tell me exactly what it's doing
[00:12:47]
and give me information to help me decide whether it's going to help solve my problem.
[00:12:53]
I might not stick around there.
[00:12:56]
It's certainly not going to be a good experience looking through that package documentation.
[00:13:01]
Because that's the first question I want to answer.
[00:13:04]
Yeah. The thing is, like, the Elm ecosystem is pretty small for good and bad.
[00:13:10]
And in this case, like, if you have two alternatives, or even like four,
[00:13:15]
like, you can spend a little more time digging whether a specific package works for you.
[00:13:23]
Whereas in JavaScript, like, you have 200 packages for the same thing.
[00:13:31]
And yeah, you really want to go to the one that strikes you the most.
[00:13:36]
Right. But if it's like a somewhat subtle thing, if it's like, oh, it's a form package,
[00:13:44]
and I look at the readme, and I don't understand, like, what are the limitations?
[00:13:52]
What are the, like, what are the things I can and can't do with this?
[00:13:56]
Then I'm not going to, and if I can't, like, find a live demo somewhere,
[00:14:01]
then I might not dig into that much further,
[00:14:04]
because I'm going to end up going to something else.
[00:14:07]
And it's going to have this mystique that I'm not going to want to approach it.
[00:14:10]
Yeah, what you say is that you want to know about the limitations of a package.
[00:14:15]
You want the package author to be honest about something, even if it sells not as well.
[00:14:22]
Yeah, totally.
[00:14:23]
Which is okay, because we're usually not getting paid for open source work anyway.
[00:14:28]
Yeah, I was just having some interesting discussions with Ryan,
[00:14:34]
the author of Elmland and Elm SPA,
[00:14:38]
and we were kind of talking about, you know, Elmland or Elm SPA.
[00:14:43]
Elmland is sort of a new version of Elm SPA versus Elm Pages,
[00:14:47]
because v3 is sort of blurring the lines a little bit,
[00:14:51]
because with Elm Pages v2, it was a much more narrowly scoped tool
[00:14:56]
that was generating static sites.
[00:14:59]
And with v3, you know, a site with authentication,
[00:15:03]
you know, a site with user-specific dynamic content
[00:15:09]
is now a use case that Elm Pages v3 supports.
[00:15:12]
So it starts to get blurry.
[00:15:14]
But so I tried really, it took a lot of thought actually,
[00:15:20]
to try to concisely summarize what is it that would make something not a good fit for Elm Pages v3.
[00:15:29]
And what I finally came up with is like,
[00:15:33]
well, there's this sort of architectural decision that you're making by using Elm Pages v3,
[00:15:38]
which is that I would like to build an application which communicates with an Elm backend.
[00:15:45]
That backend could be your build server as you generate your static pages,
[00:15:50]
or it could be a traditional server, or it could be a serverless function.
[00:15:54]
But there's some sort of Elm backend context,
[00:15:58]
and every time you navigate to a page,
[00:16:00]
it is communicating with that Elm backend to resolve data
[00:16:04]
and then sort of bootstrap the page with that data.
[00:16:08]
That, I believe, is a very compelling pattern,
[00:16:12]
but that's a big architectural decision.
[00:16:15]
And I think that it's a compelling story that is a very strong way to build an application.
[00:16:22]
But there are definitely certain clear-cut cases where it's not going to be a good fit.
[00:16:27]
For example, if you're building a one-screen game,
[00:16:31]
then that set of features isn't going to really help you with that.
[00:16:35]
And loading textures and things like that is not what the Elm Pages backend task abstraction is designed for.
[00:16:43]
It's not good for going off for 100 seconds and loading something.
[00:16:48]
You want that done asynchronously in the background.
[00:16:51]
It doesn't mean you can't use it, but it's not optimized for it,
[00:16:55]
it doesn't really need the features that Elm Pages v3 gives you.
[00:16:59]
Yes, exactly.
[00:17:01]
And similarly, you can use that rule of thumb,
[00:17:05]
is this feature set serving my needs for the use case I'm building for?
[00:17:10]
And do I want to make this architectural decision?
[00:17:15]
So that's what I finally realized is,
[00:17:17]
OK, a lot of the more dynamic apps with authentication and things like that,
[00:17:25]
you could choose Elm Land or Elm Pages.
[00:17:29]
But the differentiator is, do I want to use this architecture?
[00:17:33]
Because there are trade-offs that are associated with that.
[00:17:36]
Do you want to go all-in on using things that having a backend allows you to do?
[00:17:43]
Cookie-based authentication and being able to do server-level redirects
[00:17:50]
and being able to submit form data and handle that in the same context
[00:17:56]
using the form API.
[00:17:58]
If you want to use those patterns in that architecture,
[00:18:02]
then it's going to be a good fit.
[00:18:04]
But not everybody is going to want to use that architecture.
[00:18:07]
So that's the differentiator.
[00:18:09]
And it's not like one of them is good or bad,
[00:18:13]
but you need to tell people very clearly,
[00:18:15]
you need to help them make that decision.
[00:18:18]
Because you're the author of the tool, you have all of this context,
[00:18:22]
and somehow you need to distill that down to the relevant information
[00:18:27]
that someone needs to make a decision.
[00:18:28]
Because that's what they're trying to do.
[00:18:30]
They navigate to your tool, and the first thing they're trying to do
[00:18:33]
is make a decision, is this relevant to me?
[00:18:36]
Is this usable? And are there alternatives that would be better?
[00:18:41]
So you need to help them make that decision.
[00:18:43]
Absolutely. Yep. I think you're completely right.
[00:18:46]
And then once you've decided that, you probably want to figure out
[00:18:51]
how to use it.
[00:18:52]
And again, if you land on a tool, you go to the Elm Review package docs,
[00:19:00]
you understand what sort of use cases it helps you solve,
[00:19:05]
you decide you want to use it.
[00:19:07]
How do I actually do something, anything, right?
[00:19:11]
As quickly as possible.
[00:19:13]
I think of this actually very similarly to how I think about
[00:19:17]
the coding discipline of do the simplest thing that could possibly work,
[00:19:22]
or finding the shortest path to green,
[00:19:25]
and taking small steps to connect things where it's working in between.
[00:19:31]
You don't want a long feedback cycle where it's like,
[00:19:35]
okay, do these 100 steps, then you're all set.
[00:19:39]
Then you can evaluate whether you like this package or not.
[00:19:42]
Then you can evaluate whether you like it,
[00:19:46]
and then you'll know whether you've done those 100 steps correctly
[00:19:49]
at the end of the 100 steps.
[00:19:51]
Oh, yeah. There's that thing as well. Yeah.
[00:19:54]
I was still in the evaluating phase of the package,
[00:19:57]
where you want to know whether it fits your use case well,
[00:20:03]
and whether there are any gotchas with it.
[00:20:06]
Exactly. Yes.
[00:20:08]
That's going to be a super frustrating experience on both accounts,
[00:20:11]
where you're holding your breath, am I doing these steps correctly?
[00:20:14]
You're like, I don't have time to do 100 steps.
[00:20:17]
I haven't decided whether to commit to this yet.
[00:20:19]
I'm not like, I'm integrating this tool now.
[00:20:23]
You need to give an ELE demo.
[00:20:27]
You need to give a quick start guide.
[00:20:30]
I'm not sure if Elm Review has this right off the bat,
[00:20:34]
but the Elm Review dash dash template flag is a great way to try it.
[00:20:40]
You can say, here you go.
[00:20:42]
Here's a single command.
[00:20:44]
You npm install dash g, and then you run this one command.
[00:20:48]
You don't even need to do that.
[00:20:50]
You can just install it through npx.
[00:20:53]
You can just npx it.
[00:20:55]
Or you used to be able to. I don't remember.
[00:21:00]
Sure enough, you do have that first thing.
[00:21:04]
You've got it under a nice simple heading.
[00:21:08]
Let's look at Elm Review's docs.
[00:21:10]
The first thing I see is a topic sentence.
[00:21:13]
Elm Review analyzes Elm projects to help find mistakes before your users find them.
[00:21:17]
Screenshot. That's awesome. Now I know what it does.
[00:21:21]
I get a taste of the experience. It's a single sentence.
[00:21:24]
It's not like a paragraph that I'm like, oh, do I have to decide what's meaningful in this long paragraph?
[00:21:31]
It's a single sentence. Then there's a new heading.
[00:21:34]
What does Elm Review do?
[00:21:36]
It gives you a sense of what you're going to use it for.
[00:21:39]
And then there's a new heading. Try it out.
[00:21:41]
And it does indeed have the quick start command npx elmreview –template. Amazing.
[00:21:48]
I am a happy customer if I'm going through these docs and trying to evaluate whether you use this.
[00:21:54]
I'm glad to hear it.
[00:21:56]
But I'm sorry, I'm not actually going to pay you. I was a little misleading. Sorry, Jeroen.
[00:22:03]
It was worth the effort of doing all those years of work just to see whether you would pay me.
[00:22:11]
I would hypothetically pay if there were a way to do that.
[00:22:17]
As you say, you want the quick feedback. So there are multiple ways to do that.
[00:22:22]
So in the case of Elm Review, it's a bit of a peculiar story where you have to install the tool and then choose your configuration.
[00:22:31]
So I have this try it out section that tells you to use templates with a predefined configuration.
[00:22:37]
But that's like a pretty specific use case.
[00:22:40]
In most cases, let's imagine you just have a dict package.
[00:22:45]
Then just a simple example that you could copy paste into a REPL, that would be very sufficient.
[00:22:53]
You don't need anything more.
[00:22:55]
And that's great because it also makes a perfect example for your function and it makes it very clear what something does.
[00:23:04]
So that's great.
[00:23:07]
In some cases that are more complex, you could have a bigger code section.
[00:23:13]
But if you want people to play with it, like something visual or it's something a little bit more complex.
[00:23:18]
Let's say you want to parse a CSV, then you could write an LE.
[00:23:24]
The problem with the LE though is that sometimes I think it always uses the latest version of your package.
[00:23:31]
So older versions of your package will have documentation that is broken.
[00:23:36]
Maybe that will be fixed in the future.
[00:23:40]
But the essence of the idea still holds is you want something that people can just go to without having to install your package,
[00:23:51]
without having to create a small new project to try things out.
[00:23:55]
You don't even have to force people to use Elm Reactor or something.
[00:24:01]
And they can play with it and they can see, does this fit? Does this work?
[00:24:06]
Yes, no, let's go to the next package or let's try to fix my immediate problem that I was trying to solve.
[00:24:14]
In the case of something like Elm GraphQL, that is about code generation, that's a lot more complex.
[00:24:22]
So I think what you do, or I know what you do, is to have an example project where you have a GraphQL schema from which you generate a lot of code.
[00:24:34]
And if I remember correctly, you checked in the code so people can see it, can see the generated code.
[00:24:41]
And that I find to be very important.
[00:24:44]
I've seen a few places where you had to go in yourself and regenerate those files to see what they looked like.
[00:24:54]
But I wanted to see, if I'm curious or if that's important to me, how those generated files will look like.
[00:25:02]
So I think it's very important that you check them in so that they're available on GitHub and people can just see them.
[00:25:08]
So that's a very good thing that you've done.
[00:25:11]
But yeah, sometimes you need a project, sometimes you just need a code sample.
[00:25:15]
Whatever makes it very easy for people to try it out is good.
[00:25:20]
Right. Yeah, as you say, because it involves code generation.
[00:25:23]
If it's just a vanilla package, then if you can give an LE link, I really think you should.
[00:25:30]
Because if you can give a simple self-contained, like LE requires that it is self-contained.
[00:25:36]
So if you can give that, it forces you to write a very simple example.
[00:25:40]
And it gives people something shareable, they can play around with it.
[00:25:44]
And they can extract it into their own project from some working code.
[00:25:49]
Not some readme comment that they have to trust.
[00:25:53]
They can actually see it and even tweak it and then integrate it into their project.
[00:25:58]
I think that it's really good to have a variety of different types of content as well.
[00:26:05]
Because different people, and over the course of doing different types of tasks,
[00:26:11]
will want content presented in different ways.
[00:26:15]
So for example, the source code itself, even like you said, generated source code.
[00:26:21]
Perusing that, some types of users might want to say,
[00:26:25]
well what is this actually doing to understand it?
[00:26:27]
And someone else might never want to look at that.
[00:26:29]
They might want to look at an actual working example,
[00:26:33]
even if it's not an LE because it's using generated code.
[00:26:36]
They might want to see a deployed example that makes GraphQL requests
[00:26:39]
and inspects the network tab.
[00:26:42]
And someone else might want to play around with it locally and run the code generator.
[00:26:47]
Someone else might want to read a short guide.
[00:26:51]
And these are all different formats that people have different styles.
[00:26:56]
And some people read through the test folder.
[00:27:00]
I actually pretty commonly will go through a project and read through the test folder.
[00:27:03]
I consider that to be part of a project's documentation.
[00:27:07]
Yeah, I agree.
[00:27:08]
Part of the reason why I would like to see your generated code is because,
[00:27:12]
or for Elm GraphQL, is because a code generator will produce Elm modules,
[00:27:21]
and that's the API that I have to work with usually.
[00:27:25]
So whenever I choose to work with a package, I want to know the API.
[00:27:31]
And if your API is the generated code, then I kind of need to see it.
[00:27:35]
Otherwise, it's very blurry or very fuzzy for me.
[00:27:39]
Yes. Actually, that makes me think, like,
[00:27:43]
I probably could take that Elm.json file or the docs.json file
[00:27:49]
for the generated Elm GraphQL example that hits the GitHub API.
[00:27:55]
What is the docs.json file?
[00:27:57]
Docs.json file is an encapsulation of all of the exposed values,
[00:28:04]
types, and functions for a package along with their corresponding documentation.
[00:28:10]
So that is what the package docs present to us in a nice format on a site.
[00:28:15]
I could ship those.
[00:28:16]
I could ship that and then give people a link to documentation.
[00:28:21]
That would be another cool way to present that information for a generated API
[00:28:25]
using Elm Doc Preview.
[00:28:27]
Aha, Elm Doc Preview. What the hell is that?
[00:28:30]
Elm Doc Preview is a very good tool.
[00:28:33]
We're in the glossary section.
[00:28:36]
That's right. Exactly. Exactly.
[00:28:38]
So Elm Doc Preview is a really nice tool that lets you, on your local machine,
[00:28:43]
it lets you do a live reloading server that will show you your package documentation
[00:28:50]
for an Elm package or compiler errors if there are any.
[00:28:54]
It live reloads as you update your documentation.
[00:28:57]
It's an invaluable tool for package authors.
[00:28:59]
You can also use it for displaying documentation for application code as well.
[00:29:04]
You can define an Elm-application.json file,
[00:29:09]
and you can use it for in-house application documentation too,
[00:29:13]
which is kind of interesting.
[00:29:14]
Or you can use the Elm Doc Preview site to share links to people that will present your,
[00:29:24]
if you check in the docs.json that you get by running elm make dash dash docs equals docs.json,
[00:29:32]
that's how you generate the docs.json file for an Elm package.
[00:29:36]
If you share that, if you commit that docs.json,
[00:29:40]
then you can share a live preview link of pending documentation.
[00:29:45]
And that is a really valuable process for unpublished packages that you want to get feedback on, for example.
[00:29:52]
Absolutely. Yeah, it's a really valuable tool because often you're writing documentation
[00:29:58]
and you're not sure how it's going to look like,
[00:30:01]
and you write it and then you don't notice problems with it.
[00:30:06]
That will be obvious once you've published it.
[00:30:08]
So for instance, like if you indent some code in your documentation,
[00:30:14]
that will be displayed as Elm code.
[00:30:17]
But if you don't indent it correctly, then it might not be showing that way,
[00:30:22]
and then everything will be on one line and it will be very ugly.
[00:30:26]
So you don't want to notice that after you've published it.
[00:30:30]
You don't want to fix a documentation issue, republish,
[00:30:34]
see that it's still not looking okay, and then republish, and so on and so on.
[00:30:39]
There are also a few things that the Elm package website doesn't handle correctly,
[00:30:45]
like markdown tables.
[00:30:47]
Great idea in theory. In practice, it's not looking great at all.
[00:30:52]
So don't use those.
[00:30:54]
And if you use Elm doc preview, you will notice that it's not going to look okay.
[00:30:59]
There are a few issues, like if you have the add docs annotations
[00:31:05]
that are done in slightly incorrect ways,
[00:31:09]
then they're not going to show up okay in the package website.
[00:31:12]
So you also want to know about those early on.
[00:31:15]
So yeah, Elm doc preview, awesome tool to write your docs
[00:31:19]
and to be able to read through them in a much easier way,
[00:31:23]
like the way that your users would.
[00:31:27]
Instead of having to go through your docs that are spread out all over your Elm code,
[00:31:34]
which is not as great an experience.
[00:31:37]
It's also very motivating to see what needs documentation and what doesn't
[00:31:43]
and just read through a live preview of your docs
[00:31:47]
in that layout of a package documentation site.
[00:31:51]
And for me, just seeing something I don't like or that's missing
[00:31:56]
makes me want to go write it.
[00:31:58]
So I started to get that little kick to go do it.
[00:32:01]
There's one thing where you have to have a valid docs.json file
[00:32:07]
to be able to preview your docs.
[00:32:10]
And that means that you need to have written documentation
[00:32:13]
for every exposed thing.
[00:32:16]
In practice, if you want to see it really quickly
[00:32:20]
and without documenting some of the modules,
[00:32:23]
then you're going to add like empty documentation comments or to-dos,
[00:32:30]
which is probably a little bit better because it will be more obvious.
[00:32:35]
Yeah, that's a good idea.
[00:32:37]
I usually do empty ones, but yeah, to-dos is a good idea.
[00:32:40]
But I do it in tandem with your no missing documentation Elm review rule.
[00:32:45]
I think that's what it's called.
[00:32:46]
Yeah, docs.nomissing.
[00:32:48]
We can talk about those afterwards.
[00:32:51]
I kind of mentioned this before, and we got lost in thought, I guess.
[00:32:57]
But the one reason why we have good documentation in Elm
[00:33:01]
is because there are sections built in.
[00:33:05]
So every module that you expose is a different page or different section,
[00:33:14]
however you want to call those, on the package website,
[00:33:17]
meaning that not everything has to be in the README,
[00:33:21]
which I think is pretty good.
[00:33:24]
Not sure whether it's sufficient.
[00:33:26]
In a lot of cases, yes.
[00:33:28]
In some cases, maybe not.
[00:33:29]
But it's a pretty good thing to have at least.
[00:33:33]
So yeah, just the fact that you can separate some documentation from others
[00:33:38]
is good.
[00:33:39]
So for instance, if you have like one module,
[00:33:42]
which is a lot of tiny helpers with plenty of functions
[00:33:46]
that are not very important to the rest of the API,
[00:33:50]
then you can separate those into one module,
[00:33:53]
and they don't pollute, they don't waste space
[00:33:57]
for the more important modules of your API.
[00:34:00]
So I think that's a pretty important part of why docs are pretty good
[00:34:04]
as a starting point.
[00:34:06]
I totally agree.
[00:34:08]
And just to put a fine point on that mechanically,
[00:34:11]
what you're describing is so when you're writing an elm package,
[00:34:16]
you can write doc comments, which is just a special comment format.
[00:34:22]
You can write that for your top-level values,
[00:34:26]
and you can also write that for the module.
[00:34:28]
So the module has its docs, and each function and exposed value has its docs.
[00:34:34]
You use an annotation in the top-level module's docs
[00:34:39]
to list out all of the exposed values that you want to document.
[00:34:44]
So you can group them into sections.
[00:34:46]
So you can say, wiring up a form,
[00:34:49]
here's the init update view function for the form.
[00:34:52]
And then you can say, defining a field,
[00:34:56]
here's the checkbox and whatever functions for building a field.
[00:35:00]
And you can group those into sections using Markdown
[00:35:03]
because the docs use Markdown format.
[00:35:05]
So if you use the hash hash for an H2 heading,
[00:35:10]
it separates it into headings.
[00:35:12]
And you can even link to those headings.
[00:35:14]
So you can link somebody.
[00:35:16]
You have to sort of open up the inspector tool
[00:35:19]
and click to it because it's not linked at the moment,
[00:35:22]
but it gets the job done.
[00:35:24]
Yeah, you kind of have to guess also what the name of the link is
[00:35:27]
or what the href for the link is.
[00:35:30]
I find it with the inspector.
[00:35:32]
I click on it with the web inspector, yeah,
[00:35:34]
and then copy that.
[00:35:36]
You can try to guess it, but if you have something
[00:35:39]
with a few weird symbols, like, yeah,
[00:35:41]
just use the inspector.
[00:35:43]
That's going to have a better time.
[00:35:45]
Yeah, but that's invaluable.
[00:35:47]
And I would say, like, I notice when I'm reading documentation,
[00:35:51]
I will very frequently, like, often the only thing I read
[00:35:55]
in a whole page are the headings.
[00:35:58]
And that tells me whether or not something's relevant to me.
[00:36:01]
So, like, for example, like, you totally nailed this
[00:36:05]
for my preferences of docs, but I think this is
[00:36:09]
a pretty general best practice for docs in Elm Review.
[00:36:12]
So the review.fix module in Elm Review,
[00:36:15]
the top level describes what are fixes.
[00:36:19]
Like, what the heck is this thing, right?
[00:36:21]
Of course, there's a whole set of associated types
[00:36:24]
and functions and everything, but up front it gives you
[00:36:27]
a few things.
[00:36:28]
So it says guidelines, right?
[00:36:30]
Maybe that's the first thing you want to know.
[00:36:32]
Like, I'm writing a rule.
[00:36:33]
When would I write a rule?
[00:36:34]
But maybe I don't care about that right now.
[00:36:36]
Maybe I'm trying to, like, I know I want to write a rule.
[00:36:39]
I'm not looking for guidelines.
[00:36:41]
I want to mechanically do that.
[00:36:43]
Then you keep scrolling.
[00:36:44]
You don't look at that heading, right?
[00:36:46]
When, parentheses, not to provide an automatic fix.
[00:36:50]
If you are looking for the mechanics of it,
[00:36:53]
again, you keep scrolling.
[00:36:54]
Okay, now creating a fix.
[00:36:56]
Ah, maybe that's what I want to do.
[00:36:58]
Now you see the associated types and values
[00:37:02]
for creating a fix.
[00:37:04]
So, yeah, I think, like, I think when writing documentation,
[00:37:09]
it's important to keep in mind how people are going to consume it,
[00:37:12]
which is they're going to skim, they're going to skip over
[00:37:15]
headlines they don't care about, and that's okay.
[00:37:18]
That's not a personal failing of yours that people don't read
[00:37:22]
through top to bottom.
[00:37:23]
That's just not how people operate.
[00:37:25]
They don't read headlines.
[00:37:28]
They're there for a reason.
[00:37:30]
Put them in the top for a reason.
[00:37:33]
But it really is a choose your own adventure.
[00:37:36]
Actually, before we recorded, you and I were talking about
[00:37:40]
Zelda Breath of the Wild and Tears of the Kingdom and how cool
[00:37:44]
this sort of choose your own adventure style of, like,
[00:37:46]
an open world game is where you can bounce around.
[00:37:50]
You can, whatever, go straight to the final boss and skip all
[00:37:53]
the powerful items and upgrades, or you can do every possible
[00:37:58]
side quest and learn every mechanic of the game before
[00:38:02]
going to the final.
[00:38:03]
You can do it whatever order you want.
[00:38:05]
That's how people do docs.
[00:38:07]
They go in to do a job, and they're not going to do it in
[00:38:10]
the linear order you expect most of the time, or they might.
[00:38:13]
Yeah, first of all, like, I think, as you say, like,
[00:38:16]
you can skim through the headings, and I think it could
[00:38:19]
be valuable to have, like, a table of contents at the top
[00:38:22]
of every page or somewhere on the page.
[00:38:25]
That could be interesting.
[00:38:28]
But, yeah, so you describe the mechanics of how you write
[00:38:33]
documentation for a module.
[00:38:36]
So at the top of the module, you have a module documentation,
[00:38:39]
so curly braces, dash, pipe, some text, and at the end,
[00:38:44]
the closing, dash, curly brace.
[00:38:48]
And in between those, you write some text, some headings,
[00:38:52]
and references to functions.
[00:38:54]
And the thing that I really like about this is you decide,
[00:38:59]
based on how you write or where you write those add docs
[00:39:03]
things, how things will be presented.
[00:39:06]
So if you, the way that the docs are shown do not depend on
[00:39:12]
where they're defined in the page, because they could be,
[00:39:17]
because in Elm there's hoisting everywhere, so the Elm could
[00:39:22]
choose, well, this function is defined before this one,
[00:39:25]
so I'm going to show that one before.
[00:39:28]
But no, it's you define by saying add docs function A,
[00:39:33]
and then later add docs function B, that function A will be
[00:39:37]
displayed before function B.
[00:39:39]
And if you put it in a section or after a section header,
[00:39:44]
then it's going to show up in that section.
[00:39:46]
And you can write those, the things however you want.
[00:39:50]
So you can, as you say, you can write a story.
[00:39:52]
That's kind of like how I like to see it.
[00:39:55]
If you have a story to tell, if like maybe you don't need to
[00:39:58]
have a story for writing a dict package.
[00:40:04]
But in the case of Elm Review, there's a lot of things that I
[00:40:09]
need to explain, and some of them need to be first,
[00:40:12]
like guidelines, which I think when they're not details,
[00:40:17]
should be read before you read the rest.
[00:40:21]
Although you do whatever you want.
[00:40:24]
But like I'm expecting that by default people will read
[00:40:28]
things from top to bottom.
[00:40:30]
And you can, yeah, you can choose how things will be
[00:40:32]
displayed, and I found that to be very powerful.
[00:40:35]
And there's a cool thing that Elm format does as well
[00:40:40]
with add docs.
[00:40:42]
So whenever you add those add docs things,
[00:40:45]
it changes the exposing clause in your module,
[00:40:51]
the first line in your module declaration.
[00:40:55]
So module, module name, exposing,
[00:40:58]
and then plenty of things.
[00:41:00]
So if you have add docs for those,
[00:41:02]
it will reformat them in the same order.
[00:41:05]
So if you have add docs ABC and then next line add docs DEF,
[00:41:11]
then you will have two lines, ABC and then DEF,
[00:41:16]
in the exposing clause.
[00:41:18]
And I use that as well in my application code.
[00:41:22]
So if I want to make a, let's say, button module,
[00:41:27]
then I write the documentation so that the API is shown
[00:41:33]
as a table of contents in a way at the very top of my file.
[00:41:37]
So usually I have something like a section how to create,
[00:41:43]
and I have the type of the button,
[00:41:46]
so add docs button, and then also the init or the different
[00:41:50]
variants for init.
[00:41:52]
And then I have a section with all the with functions
[00:41:55]
if I choose to do so, and then a section on how to transform
[00:41:59]
that to HTML, something like that.
[00:42:02]
And then you can see in the exposing clause, well,
[00:42:06]
button, comma, init, next line, with something, with something,
[00:42:10]
with something, and at the end to HTML.
[00:42:13]
And you can even put those things onto more lines,
[00:42:16]
so you have with large size, with small size, with medium size,
[00:42:21]
and then on the next line with color red, with color blue.
[00:42:26]
These are terrible examples, but the way that I try to do those
[00:42:31]
is I write them so that every line deals with one thing.
[00:42:35]
So if you want to deal with the size of the button,
[00:42:38]
you have one line with all those.
[00:42:40]
If you want to talk about the color, you have one line
[00:42:43]
with all those, maybe also the color type or something.
[00:42:47]
And I find that just to have this thing is already very valuable,
[00:42:51]
so that's what I do in my application code,
[00:42:54]
and that's why I push at work to have some documentation,
[00:42:58]
even if it's just for that, because that makes things a lot simpler.
[00:43:01]
Cool. When you say some documentation,
[00:43:04]
are you mostly doing empty doc comments for internal things,
[00:43:08]
or do you actually write something for these internal APIs?
[00:43:12]
So if it's for application code, I usually don't write any documentation
[00:43:16]
because it's not mandatory there.
[00:43:19]
I try to have better names.
[00:43:22]
Usually things are pretty self-explanatory,
[00:43:26]
especially because at work we have this way of working,
[00:43:30]
we have several patterns that we use over and over.
[00:43:33]
So once you know it, you don't have to explain things again.
[00:43:37]
So it does not make sense to explain button.withColor
[00:43:41]
when you have so many other modules where you have withColor as well.
[00:43:46]
It makes a lot more sense in package code, I think,
[00:43:49]
because people might be new to the pattern,
[00:43:53]
and you also don't need to have as much of a great documentation experience
[00:43:59]
maybe at work, especially when you have colleagues that are right next to you,
[00:44:04]
and because for application code, time is more precious
[00:44:07]
than for open source maintainers.
[00:44:10]
I think it would depend if there's that one part of the code base
[00:44:16]
where new hires have to pair with the one person at the company
[00:44:22]
who really actually knows how to use this thing
[00:44:25]
in order to get up and running,
[00:44:27]
then maybe that is a case where it's good to do that.
[00:44:31]
I would say, because I am a big fan of self-documenting code,
[00:44:37]
and I will admit I very rarely write documentation for application code,
[00:44:45]
and I don't think that's a bad thing.
[00:44:47]
I would say, to me, I'm not a fan of writing documentation
[00:44:53]
when a good name would achieve the same thing.
[00:44:57]
I think it's sort of like going down the chain.
[00:45:02]
I think you should always prefer communicating something
[00:45:06]
through good naming and good API design when possible,
[00:45:11]
and also through a good, easy way to use something.
[00:45:16]
A command line interface and automation rather than a cookbook.
[00:45:21]
Here are five different steps, right?
[00:45:23]
That might be calling out to automate it.
[00:45:25]
So like, oh, I was a good boy and I wrote some documentation for this.
[00:45:29]
It's like, well, maybe you weren't such a good boy.
[00:45:31]
Maybe you should have automated that.
[00:45:33]
It's also because function names, that's what you see when you read code, right?
[00:45:39]
You can go to the documentation in your IDE,
[00:45:43]
sometimes on GitHub or through searching for yourself in the package website.
[00:45:49]
But it's much easier to see the function name,
[00:45:53]
and if that conveys the meaning, then that's all you need.
[00:45:57]
When I write bash code, or sorry, when I look for a command to do something
[00:46:03]
and someone on StackOverflow says,
[00:46:05]
oh, you should run this command, pipe this command, this slash pipe this command,
[00:46:12]
and I'm like, I know none of these commands,
[00:46:14]
or there are some of these flags that are new to me.
[00:46:19]
Well, now I need to read the documentation.
[00:46:21]
So hopefully it's going to be good, but like for bash commands,
[00:46:25]
everything is in like one manual.
[00:46:28]
It's one readme-ish document.
[00:46:31]
So it's hard to find the information you want sometimes.
[00:46:34]
And also, like, there's just a lot of things.
[00:46:37]
So yeah, good names is always preferable.
[00:46:40]
But if you can have both, go for both.
[00:46:43]
Right. And also, I mean, this is sort of maybe so obvious
[00:46:48]
that we wouldn't think to mention it here
[00:46:50]
because we sort of talk about this all the time.
[00:46:53]
But the API design is part of the documentation.
[00:46:57]
Where you look to find a function, how you group together,
[00:47:03]
and it's actually something I put a lot of thought into.
[00:47:07]
It's actually quite difficult to get right.
[00:47:09]
Do you have one big module with a bunch of things thrown in there?
[00:47:14]
Do you have a lot of small modules that have things clearly separated?
[00:47:18]
I think the way you organize things into Lmodules
[00:47:22]
is really a part of how you're presenting these concepts to users.
[00:47:27]
What should they think of together?
[00:47:30]
But it's also an ergonomic thing.
[00:47:32]
How many imports are they going to need?
[00:47:34]
And also, it's a sign.
[00:47:36]
If you have a lot of modules, is that a lot of concepts?
[00:47:39]
If you have a lot of modules,
[00:47:42]
but you end up having to import all of them every time,
[00:47:45]
that might not be a great experience.
[00:47:47]
So it's really a delicate process to slice things up into a meaningful way.
[00:47:54]
But you're presenting these ways of grouping things,
[00:47:59]
not just in terms of how you import them, but how you think of them,
[00:48:03]
and also how you read them.
[00:48:05]
Because Elm package documentation is organized by module,
[00:48:09]
it really is like the pages in your documentation.
[00:48:13]
And I think that's a brilliant part of it.
[00:48:15]
And again, back to your sort of opening sentiment
[00:48:18]
about the baseline for quality in Elm documentation.
[00:48:22]
I think that's part of it, is things are grouped
[00:48:25]
where a module is a page in your docs.
[00:48:29]
And so you import one thing,
[00:48:32]
you read the docs about that one thing you imported,
[00:48:35]
and it's all grouped together logically.
[00:48:38]
So that really shapes the way I write documentation.
[00:48:42]
So for example, like in Elm Pages v3,
[00:48:45]
back-end task is a big part of it.
[00:48:47]
So I have a back-end task.env module,
[00:48:51]
which is a pretty small module.
[00:48:53]
It's got a couple of things for expecting to get an environment variable
[00:48:57]
and errors that can come up when you do that.
[00:49:00]
Or back-end task.file, that is a module that is, you know,
[00:49:04]
knows how to read files that might have some front matter formatting in them,
[00:49:10]
or it might not, read a raw file, read a JSON file, things like that.
[00:49:13]
It's a pretty mechanical module, but it also sort of describes
[00:49:19]
that this is something that Elm Pages allows you to do, read from files.
[00:49:24]
But it also references back to the back-end task API,
[00:49:29]
because this is the sort of core abstraction.
[00:49:32]
And so this module has really, it breaks down the mental model.
[00:49:38]
It breaks down a conceptual guide,
[00:49:40]
and it links out to all these different ways you could use it.
[00:49:43]
So this is the opportunity to present these sort of key concepts
[00:49:48]
and the API for how to use this basic building block.
[00:49:52]
And then that in turn links out to all these more specific ways to use them,
[00:49:58]
like back-end task.custom is another huge piece, right?
[00:50:02]
It's allowing you to run arbitrary code in a JavaScript environment
[00:50:07]
that you can have access to and encode data to send to it, decode data to get back.
[00:50:13]
It calls an async JavaScript function, right?
[00:50:16]
That is, that's a big concept to chew off.
[00:50:19]
If that was part of the back-end task module's documentation,
[00:50:23]
it would be kind of overwhelming.
[00:50:25]
It would be bombarding the user with information to understand
[00:50:31]
when they might just be like, what is a back-end task?
[00:50:35]
I'm new to Elm pages.
[00:50:36]
But it's linked to, and there's a short set of bullet points at the top of back-end task.
[00:50:42]
So it describes what is a back-end task in a concise one-sentence way,
[00:50:47]
and then what are the ways you can use it?
[00:50:51]
And you can click to those and choose your own adventure from there,
[00:50:54]
or you can continue reading about back-end tasks.
[00:50:56]
So I think the way you group these and organize them is really key.
[00:51:00]
And again, it's like one module is one page in your documentation.
[00:51:05]
So the title of that module, the things that are grouped there, the scope of it,
[00:51:10]
how many concepts go there are all really important considerations.
[00:51:13]
Yeah, and it's really hard for us to choose what goes into each.
[00:51:18]
Like, should I split this thing into more modules?
[00:51:22]
I know, for instance, like Elm UI has asked themselves the same question,
[00:51:27]
like, oh, I have all these borders.
[00:51:30]
Should that be their own modules or module?
[00:51:34]
Or should it be in the same module as these other things?
[00:51:38]
And sometimes it's clear-cut, sometimes it's pretty hard, or it's arbitrary.
[00:51:44]
It actually requires some surprisingly nuanced technical tricks in the Elm code sometimes
[00:51:50]
to support that, like a common one being avoiding circular imports.
[00:51:55]
And so in Elm, the Elm compiler forbids things importing each other.
[00:52:02]
Modules can't import something that imports them.
[00:52:05]
And therefore, you often need to use this trick of sort of having something scoped
[00:52:11]
where it's exposed to the package.
[00:52:13]
What that means, we've talked about in previous episodes,
[00:52:16]
you have an Elm.json file, which for an Elm package gives you a key of exposed modules.
[00:52:24]
And that's where you list out the modules that will be part of your public API.
[00:52:28]
But you can have some non-exposed modules, and those non-exposed modules
[00:52:34]
allow you to have types and functions which are visible to your whole package,
[00:52:40]
but not visible through the exposed package.
[00:52:43]
But you can expose them through type aliases, which is why you'll sometimes see
[00:52:47]
type alias element equals element.
[00:52:50]
What does that mean?
[00:52:52]
Well, it's a package private one.
[00:52:55]
Yeah, it's a trick.
[00:52:57]
And so that means you have a lot of possibilities for where you can expose something.
[00:53:01]
Which module do you expose that type alias from?
[00:53:04]
It could be a lot of different ones.
[00:53:06]
But I think there is something really key.
[00:53:08]
Evan has talked about this in, I think, his talk, Growing Elm Modules.
[00:53:12]
Wait, no, sorry.
[00:53:14]
Life of a File.
[00:53:16]
Evan's talk, Life of a File, he talks about how there's something to how you
[00:53:22]
grow and expand an Elm module that is centered around a type.
[00:53:26]
And I think that's really true.
[00:53:28]
It should be usually one central type and some key things on how to use that thing.
[00:53:35]
I mean, something like a data structure would be a queue structure or a stack or something like that
[00:53:43]
would be an obvious example of that.
[00:53:46]
But also back-end tasks.
[00:53:48]
But back-end tasks, again, it's subtle because there are other ways to consume a back-end task,
[00:53:53]
like back-end-tasks.custom.
[00:53:56]
So that's a module associated with that same back-end-task type, but it's some helpers
[00:54:01]
that actually aren't built around a specific type.
[00:54:04]
So it's not always clear-cut.
[00:54:07]
While we're on the topic of things that are too basic to mention, but let's mention them anyway,
[00:54:13]
one reason why Elm docs are great is because they're simple, or because Elm code is simple.
[00:54:21]
Like, I'm not going to praise it even more than I usually do, but do I?
[00:54:29]
But the thing is, whenever you have simple code, like a function that adds to numbers,
[00:54:36]
well, you have the function, you have a code sample, so if you say add 5, 7,
[00:54:43]
you can show that it does 12, returns 12.
[00:54:47]
And that's it. There are no side effects, there are no mutations.
[00:54:52]
This is all that your function does.
[00:54:56]
So it's really easy to understand, whereas in languages like JavaScript,
[00:55:01]
if you look for the documentation for arrays, the list-like type, not the erasing something,
[00:55:11]
so if you do.sort on an array, it's going to mutate it.
[00:55:19]
And that's something that can be hard to convey without mentioning it explicitly,
[00:55:27]
and that can be surprising as well.
[00:55:30]
But you don't have those things in Elm, so things are pretty simple.
[00:55:34]
And also, every function shows the type annotation, and that's very valuable as well,
[00:55:42]
because a type annotation gives a lot of information, and if you don't have it,
[00:55:48]
which is, again, the case in JavaScript, often less so with TypeScript nowadays,
[00:55:54]
well, yeah, you have a lot more information that you can use to understand what it does.
[00:56:00]
So Elm is simple, and that has great benefits, basically.
[00:56:06]
Yeah, like if you're working with a different language, JavaScript, Ruby,
[00:56:11]
it's very common, like, is this nullable?
[00:56:15]
Which, of course, TypeScript somewhat helps with, but only somewhat.
[00:56:19]
How many arguments does this take?
[00:56:21]
If I pass in zero arguments, one argument, two arguments,
[00:56:25]
are there different variadic forms of this, different arities for this function?
[00:56:31]
Is it going to return different types based on the input I give it?
[00:56:35]
Is it going to mutate the input I give it or change some global thing or perform some side effect?
[00:56:41]
Is it going to do one thing if I pass in an object, and another thing if I pass in a string,
[00:56:46]
and another thing if I pass in a buffer, and another thing if I pass in a promise?
[00:56:50]
Does it return a promise or a non-promise?
[00:56:54]
Is there going to be any effect if I just import this file?
[00:56:58]
Right. Can it throw an exception?
[00:57:01]
Yeah, what are the possible crashes that this can have?
[00:57:05]
Right. All of these things, they are just non-existent in Elm,
[00:57:10]
so I couldn't agree more.
[00:57:12]
The explicitness already, your confidence in navigating an API is so much higher
[00:57:18]
from just the bare minimum documentation in an Elm package.
[00:57:23]
Also, I mentioned, if you have a code example, like add 5, 7,
[00:57:28]
and you add a line underneath that says, this returns 7,
[00:57:34]
there's a... often what you will see is dash, dash, greater than.
[00:57:39]
So it basically does an arrow, and then 7.
[00:57:42]
And there's a tool, which is called Elm Verify Examples,
[00:57:46]
that will turn those code examples into actual tests.
[00:57:53]
So you can be sure that your code sample is correct,
[00:57:58]
that it returns what you said it did.
[00:58:02]
So that's pretty powerful as well.
[00:58:04]
I really wish I could use this for Elm review in some way.
[00:58:08]
I know. I wish that it could verify that things compile,
[00:58:13]
but unfortunately it doesn't at the moment.
[00:58:16]
But it is a very valuable tool.
[00:58:19]
Also, on the topic of code snippets, I think that's also huge.
[00:58:25]
Just having code snippets, example, output,
[00:58:29]
like when you're navigating functions in an API,
[00:58:33]
again, you want to equip the user with what is the relevant information
[00:58:37]
they're going to need.
[00:58:38]
And really, even if it seems obvious from the type signature,
[00:58:42]
having an example is very useful.
[00:58:45]
It demystifies it, and it makes it feel real.
[00:58:49]
And it's also an opportunity to give an example use case.
[00:58:54]
So I think, in my opinion, I feel very strongly that every example
[00:58:59]
is an opportunity to demonstrate a meaningful use case,
[00:59:02]
which is why I try really hard to avoid toy examples,
[00:59:08]
foobar baz, and instead try to illustrate,
[00:59:11]
why would I use this feature with real-world use cases?
[00:59:16]
Because now you're using that opportunity to convey information
[00:59:20]
in a richer way.
[00:59:21]
People are taking the same amount of time to read through something,
[00:59:24]
but you've now conveyed the kinds of things this tool would be helpful for
[00:59:28]
and best practices for using it.
[00:59:30]
Yeah, this is something that I do purposefully in Elm Reviews documentation,
[00:59:36]
is for every function that you can use to define a visitor or something,
[00:59:44]
I add an example rule.
[00:59:47]
So that's a lot of code, potentially, but you can see,
[00:59:51]
oh, I can use this for this, and also this is how you use it.
[00:59:56]
But if you just go through the documentation, you can already
[01:00:00]
just copy-paste some rules and adapt them to your needs, potentially.
[01:00:05]
I find that to be pretty interesting.
[01:00:08]
Yeah, as an Elm Review user, I find that extremely valuable.
[01:00:12]
Also, just imagine looking at with simple declaration visitor,
[01:00:17]
and you're seeing, okay, it takes a function,
[01:00:20]
no declaration, returns, list of error,
[01:00:24]
and a module rule schema, and it returns a module rule schema
[01:00:29]
which has at least one visitor.
[01:00:31]
That's okay. Yes, that's telling me some information that's useful,
[01:00:36]
but without an example...
[01:00:38]
Really hard to use, yeah.
[01:00:40]
Yeah, like, okay, well, what do I do with node declaration?
[01:00:43]
Well, actually, what you're most probably going to do
[01:00:48]
with a node declaration is you're going to do
[01:00:51]
case node.value node of, and then you're going to enumerate
[01:00:56]
the different declaration types which are imported from this module.
[01:01:00]
Also, I'm a big fan of being explicit about the imports
[01:01:04]
because you want to make it clear.
[01:01:08]
And actually, Elm Verify examples does not require you
[01:01:13]
to qualify the module you're using,
[01:01:17]
but I prefer to be explicit about using unqualified module
[01:01:23]
or qualified module references,
[01:01:25]
so putting the module name before explicitly
[01:01:28]
and putting the import to the module itself,
[01:01:31]
even the one I'm documenting.
[01:01:33]
It just makes it more copy-pastable and more explicit.
[01:01:35]
Exactly, yeah.
[01:01:37]
And also, like, when you don't qualify something in your example,
[01:01:42]
it can be hard to know whether the function that you're referencing
[01:01:46]
is defined in this file, which in some cases it will be,
[01:01:50]
or if it's a value that is somewhere else in the code snippet
[01:01:55]
or that is just omitted because it's too complex to do for the example
[01:02:00]
or too annoying to do.
[01:02:02]
But if you qualify it, then it's a lot more explicit,
[01:02:05]
and as you say, copy-pastable, understandable.
[01:02:07]
And we usually in the Elm community advise for qualified imports anyway,
[01:02:15]
so let's use that in the examples anyway.
[01:02:19]
That's my take at least, and I know you agree with this.
[01:02:23]
Yes, and also it should be as idiomatic as possible in every way.
[01:02:28]
Now, of course, people do have different styles,
[01:02:31]
and there's nothing wrong with that.
[01:02:32]
Some people really like using unqualified imports in certain cases,
[01:02:37]
and that's totally fine, but I think that it's important
[01:02:40]
to try to write in an idiomatic format.
[01:02:42]
Like, for example, if you're going to use an import alias,
[01:02:46]
use that everywhere and use it consistently in your examples
[01:02:49]
because the thing is, everybody who uses your package
[01:02:54]
will probably use that same example that you use
[01:02:58]
because you're sort of defining a convention,
[01:03:01]
whether or not you realize it, and so you should put some thought
[01:03:05]
into how you want to import things, not just like,
[01:03:07]
well, for the case of this example, I'm going to use a one-letter import
[01:03:10]
or something like that.
[01:03:13]
People take it and run with it.
[01:03:15]
Also, so naming things is important.
[01:03:19]
I am personally a fan of giving meaningful names to type variables.
[01:03:23]
Now, in the case of, you know, dict comparable a,
[01:03:30]
that might be fine.
[01:03:32]
I don't know. What do you think about that?
[01:03:35]
I think that if it's for something generic, like purposefully generic
[01:03:39]
and extremely generic, then a is just fine.
[01:03:43]
If it's for functions like map, where you have a something a
[01:03:49]
that transforms it to something b, that's very fine as well
[01:03:53]
because people understand it.
[01:03:56]
If it's for anything else where you have more insights
[01:04:00]
about the type variable, what it will hold,
[01:04:04]
what it does represent, then I would use that instead when possible.
[01:04:09]
Right. Yeah, like in the Elm Review docs, I see you, for example...
[01:04:14]
You use schema state, I think.
[01:04:16]
Schema state, module context.
[01:04:20]
So that is... and you use the naming consistently.
[01:04:25]
So at least that gives people a sense of what name to use.
[01:04:29]
I'm trying to remember in ElmGraphQL, I made a change as well
[01:04:32]
at some point where I was not using a type variable.
[01:04:36]
I didn't have a good name for this type variable,
[01:04:39]
and it actually made it a lot harder for people to understand the context.
[01:04:43]
What did I name it? The scope.
[01:04:45]
Okay, so yeah, in ElmGraphQL, a selection set decodes to a value,
[01:04:51]
and it has a scope.
[01:04:53]
The scope is a phantom type.
[01:04:55]
This is a confusing concept to introduce to people, right?
[01:04:58]
Some people might not have used a phantom type.
[01:05:00]
Some people might have used a phantom type,
[01:05:02]
but might not understand how that applies to the concept of GraphQL.
[01:05:06]
So a selection set, you know, we've discussed in the past,
[01:05:11]
it is scoped so that you can't, you know,
[01:05:15]
if you are able to take a selection set that represents getting the first name
[01:05:20]
in the scope of a user,
[01:05:23]
you can't get the first name in the scope of a product.
[01:05:28]
So the scope phantom type variable defines the scope of your selection.
[01:05:33]
So I tried to use domain language there, and I think that's really key.
[01:05:38]
Yeah, the type variable is usually something a little bit more abstract.
[01:05:44]
So especially if it's used to represent some constraints,
[01:05:49]
then it's worth giving it a good name,
[01:05:53]
like even if it's just constraints, I don't know,
[01:05:56]
I use something somewhere maybe.
[01:05:58]
Yeah, and naming is also a process.
[01:06:00]
You can always iterate to get a better name.
[01:06:04]
You don't have to get everything around the first try.
[01:06:06]
I think it's really important to notice where do you find friction
[01:06:12]
as you're reading things?
[01:06:15]
Where are you finding that you're conflicted about what names to use?
[01:06:19]
You don't have a clear concept in your head of what term to use for something.
[01:06:24]
Where are people getting confused?
[01:06:26]
Where are you finding it difficult explaining a concept to other people?
[01:06:31]
I think it's important to deliberately invest time in giving names
[01:06:35]
to these abstractions and ideas and iterating on names there.
[01:06:39]
So those are things to look for.
[01:06:42]
Also getting feedback from users is key, of course.
[01:06:45]
You mentioned at the beginning that whenever you thought about
[01:06:47]
binding documentation, you were thinking about Varisblock.
[01:06:50]
Yeah.
[01:06:52]
So as you say, writing documentation is sometimes not the most fun part
[01:06:57]
and it can be very hard.
[01:06:59]
Also, how much should I detail?
[01:07:03]
What should I detail?
[01:07:05]
It's hard sometimes.
[01:07:07]
But in some cases, things are just super complex to explain.
[01:07:11]
I remember when preparing for Arm Review V2,
[01:07:16]
I had an API to merge module context into a project context or something.
[01:07:26]
The most complex part of Arm Review's API
[01:07:31]
is how you mingle project context and module context.
[01:07:35]
And I found that to be very hard to explain.
[01:07:39]
It took me plenty of paragraphs.
[01:07:42]
And I was like, this is still not amazing.
[01:07:45]
And at some point, I figured out a different API for it,
[01:07:49]
and it was much easier to explain.
[01:07:52]
So sometimes the solution to when you have trouble explaining something
[01:07:57]
is to change the API.
[01:07:59]
Like you're explaining something that is too complex
[01:08:02]
and you should try to find a simpler way.
[01:08:06]
So that was the pain points that I had once.
[01:08:10]
And the solution was do something different.
[01:08:14]
And then as soon as you see, oh, now it's much easier to explain,
[01:08:18]
well, that's a pretty good sign that it's a good API, probably.
[01:08:21]
Exactly.
[01:08:22]
Which for the same reason, that's why if you find yourself
[01:08:28]
writing documentation, it can be a crutch
[01:08:30]
because maybe you should have been documenting something.
[01:08:34]
Maybe a hard to explain concept,
[01:08:37]
maybe lots of documentation is a crutch
[01:08:39]
for making the concept easier to understand,
[01:08:42]
making the API simpler.
[01:08:44]
So it should always be documentation should support something
[01:08:48]
that's intuitive on its own, ideally.
[01:08:51]
And you're going to have the best time when you're always considering
[01:08:55]
changing something to make it simpler,
[01:08:57]
not just documenting what you already have.
[01:08:59]
And when you count, then documentation makes sense.
[01:09:03]
Like if something is done a specific way for performance
[01:09:07]
or because there's a bug in some package, some other package,
[01:09:12]
or the web browser doesn't work as you would expect,
[01:09:16]
then yeah, add the documentation comment that says,
[01:09:20]
this is the reason why something is this way.
[01:09:24]
Right, right.
[01:09:26]
Yeah, I always love the scene in the show Silicon Valley
[01:09:29]
when they're getting user feedback on the product
[01:09:33]
and then the CEO is watching through this blind mirror thing
[01:09:38]
and watches the users in frustration improperly using the product
[01:09:43]
and he goes in and corrects them and tells them how they're all using it wrong.
[01:09:47]
But of course, feedback is only as good as your willingness to listen to it.
[01:09:53]
So I think you, not that you should necessarily do directly
[01:09:58]
what everybody tells you you should do.
[01:10:00]
That's not the right answer either.
[01:10:03]
By the way, you should not listen to this episode.
[01:10:05]
We only have garbage information.
[01:10:09]
So see ya.
[01:10:11]
Right, exactly.
[01:10:13]
Yeah, but I mean, when you're getting feedback,
[01:10:17]
it's telling you something.
[01:10:19]
And that's the fine line there is like understanding that
[01:10:24]
people are telling you pain points and hearing that they have a pain point.
[01:10:29]
If some people are trying to write documentation,
[01:10:31]
I also have a few Elm Review rules that can be helpful for that.
[01:10:36]
So there's a package called jfmangles.com slash elmreview documentation,
[01:10:42]
which has four rules, some more applicable to others than others.
[01:10:47]
So there's one that is called docs.no missing, which we mentioned before,
[01:10:51]
which reports missing or empty documentation.
[01:10:54]
So these rules can be used for application,
[01:10:57]
but they can also be used for packages.
[01:11:00]
And in this case, like for packages, it will report when it's missing,
[01:11:05]
just like the Elm Compiler would, but it also reports empty documentation,
[01:11:08]
which I think is something we should try to avoid as much as possible.
[01:11:12]
I think you disagree with it sometimes.
[01:11:15]
I personally disagree with it for map two, map three, map four, map five.
[01:11:20]
So my reasoning is that I see this quite often that people document map,
[01:11:26]
they document map two because it's more complex,
[01:11:29]
and then they don't document map three.
[01:11:31]
So the documentation is empty and same for map five, et cetera.
[01:11:36]
And the thing is like your documentation can be found in the package documentation,
[01:11:41]
but it can also be found in the ID.
[01:11:44]
And if you hover map two, you get a helpful documentation comment.
[01:11:51]
But if you hover map three, then you have nothing.
[01:11:55]
And that's not very helpful in my opinion.
[01:11:58]
So I would much rather have map three say refer to the documentation of map two.
[01:12:05]
Okay, nice.
[01:12:06]
Because now you can just, you know where to look at.
[01:12:10]
Potentially you can even click on it.
[01:12:13]
So that's why it does not, no missing reports, empty documentation.
[01:12:17]
Oh, cool.
[01:12:18]
Maybe I could even make an Elm review rule to automatically do that for my map and functions.
[01:12:23]
Potentially, yeah, that'd be fine.
[01:12:26]
There's also a docs.review add docs rule, which is a bit of a weird name.
[01:12:33]
Yeah, but I use it and it's saved me in some situations.
[01:12:37]
So thank you for that.
[01:12:39]
So we mentioned the add docs annotations,
[01:12:43]
and there are quite a few ways where you can use them
[01:12:47]
where the package documentation will not handle them correctly.
[01:12:52]
Like that the compiler will usually tell you, hey, you're missing add docs
[01:12:56]
or you're having add docs that are not expected.
[01:13:00]
But this rule will also report those for when you use it in applications
[01:13:06]
because the Elm compiler will not help you there.
[01:13:08]
But there's also cases where, for instance, if you indent add docs
[01:13:14]
or if you put it in at the very first line of your module documentation,
[01:13:19]
then your docs will not look as expected.
[01:13:23]
So if your entire module documentation is the curly braces, whatever, add docs something,
[01:13:33]
then that is literally what you will see, add docs something.
[01:13:37]
That's your entire documentation.
[01:13:39]
And I've seen this over and over again, so I've made an Elm review rule that reports about those.
[01:13:44]
And there's a few other gotchas that are similar to that.
[01:13:47]
Well, so like one of the ones that has saved me many times,
[01:13:50]
I actually wish that the IDE could do this for me automatically,
[01:13:53]
but when I rename a module, I sometimes, most times, honestly,
[01:13:59]
miss that in renaming my links within my docs.
[01:14:04]
And that Elm review rule catches it for me.
[01:14:06]
If it's pointing to a module which no longer exists, it catches that.
[01:14:09]
No, it doesn't. That's the third rule.
[01:14:12]
Okay, yes.
[01:14:14]
You're making a nice segue, at least.
[01:14:17]
So that's docs.reviewlinksinsections.
[01:14:20]
So that one is also very interesting.
[01:14:23]
As you say, you link from one module to another, from the README to another module.
[01:14:28]
And yeah, if you rename something, then things are broken.
[01:14:32]
Or if you make a typo, then things are broken,
[01:14:34]
and you don't want your users to let you know about that.
[01:14:37]
So this rule lets you know about it.
[01:14:40]
It also reports the ambiguous links.
[01:14:44]
So if you have a markdown section, so hashtag, hashtag, init,
[01:14:50]
and you have a function called init, then they will have the same href?
[01:14:56]
Yeah. Name. I think it's like the name under the hood.
[01:15:01]
The same anchor?
[01:15:03]
Name, attribute. Yeah.
[01:15:05]
So whenever you will link to that, it will go to the first one.
[01:15:10]
And you ideally want them to be different, like not ambiguous.
[01:15:18]
So this will also report that.
[01:15:21]
I think that's the one that reports it.
[01:15:23]
But yeah, something reports it.
[01:15:25]
And then there's another one that is docs.uptodate.readmelinks,
[01:15:29]
where the README is a bit of a peculiar file,
[01:15:34]
because you can see it on GitHub, and you can see it on the package website.
[01:15:39]
And depending on how you do the links, they will be up-to-date or not up-to-date.
[01:15:44]
Usually what people do is they link to the package website from the README,
[01:15:49]
and they use slash latest to specify the version, which works,
[01:15:54]
but not once you release a new version.
[01:15:57]
Now your previous version of your package,
[01:16:01]
the README will link to a function on the latest version,
[01:16:07]
and that function might not exist anymore.
[01:16:10]
So that's a problem.
[01:16:13]
So this helps replace those latest by the current version of your version
[01:16:20]
defined in your Elm.json.
[01:16:22]
And whenever you upgrade your version, it will auto-fix those.
[01:16:28]
So that's one reason that I have a very good time bumping the packages
[01:16:34]
and keeping these links up-to-date is I bump the version, I run this rule,
[01:16:39]
and all my links are correct again.
[01:16:41]
And that's just very nice.
[01:16:43]
It's definitely an example of something that is the correct thing to do,
[01:16:48]
but in practice, without automation, something that people just would not do.
[01:16:52]
It wouldn't be tenable. So it's great.
[01:16:55]
Yeah, and I remember that before I made this rule, it was like,
[01:16:59]
well, what should we do? And there was no clear cut answer.
[01:17:03]
So those are the four rules that are there.
[01:17:06]
If you can think of another one, let me know.
[01:17:09]
I definitely think there are more things to be done.
[01:17:12]
Yeah, and I mean, also somewhat relevant would be the forbidden keywords, is it?
[01:17:18]
For checking for things like to-dos.
[01:17:21]
To-do or string, is that what it is?
[01:17:23]
To-do? No, that's different.
[01:17:26]
Yeah, there's a package called sparksp.elmerview forbidden words
[01:17:31]
where you can tell it, please report all usages of to-do or replace me.
[01:17:38]
And this is whenever you make an ElmerView package,
[01:17:42]
you have this rule with replace me already in there.
[01:17:47]
So whenever you try to write replace me as a placeholder for some documentation,
[01:17:54]
for instance, this rule will at some point let you know,
[01:17:58]
hey, you should replace this.
[01:18:02]
So that's very useful as well.
[01:18:04]
Yeah, I also have a GitHub template called the ElmPackageStarter,
[01:18:08]
and this uses most of these ElmReview rules,
[01:18:12]
and I've found it pretty nice for bootstrapping a quick Elm package.
[01:18:17]
And it also links to a project of mine which we've talked about in the past,
[01:18:21]
the Idiomatic Elm Package Guide, which sort of lays out, I think,
[01:18:25]
a set of principles for how to organize your readme
[01:18:30]
and what format to manage a changelog and some boring but important things.
[01:18:36]
I think these are really important.
[01:18:39]
Having a changelog, if you create a new version of a package,
[01:18:44]
people are going to be wondering what changed.
[01:18:47]
And having an obvious format that is something you would expect across packages.
[01:18:53]
Same with an examples folder.
[01:18:55]
People in the Elm community, if they've kind of been around for a little while
[01:18:59]
and seen some packages, they're probably going to expect the GitHub project
[01:19:04]
to have an examples folder.
[01:19:06]
They're probably going to expect to have a link to the package from the GitHub readme.
[01:19:13]
They're probably going to expect to have a test suite with a badge
[01:19:17]
that shows whether the test suite is passing.
[01:19:20]
Some boring things like this that I think are worth having.
[01:19:25]
Yeah. By the way, the fact that you have the changelog
[01:19:29]
and sometimes the contributing instructions in the readme,
[01:19:35]
that's something I see sometimes and I don't think that's the place for the readme.
[01:19:40]
Especially because there are some standards where you have a file called changelog,
[01:19:47]
all caps, or usually all caps,.md, and one called contributing,
[01:19:53]
and there's also license and all those, plenty of other files like that.
[01:19:58]
Yes, and those are meaningful to GitHub and to Elm, to the Elm compiler too.
[01:20:02]
So, the license file, for example, is required by Elm.
[01:20:05]
Yeah, I wouldn't like it if the changelog was maybe also special,
[01:20:10]
at least was linked to in the package documentation.
[01:20:15]
Absolutely, yeah. And if you could, man, wouldn't that be cool
[01:20:19]
if you could kind of show the Elm diff, if you could have some syntax for the changelog
[01:20:26]
where you could say the breaking changes, because Elm diff,
[01:20:31]
when you do an Elm bump, it knows the breaking changes,
[01:20:34]
and if you could document how it changed or why it changed, that would be really cool.
[01:20:38]
Yeah, just being able to see the diff on the website, I guess,
[01:20:43]
on the package website between two versions, that would be nice as well.
[01:20:46]
Because often I see that a new package has been released on Slack
[01:20:51]
and I watch it, I open it on my phone, and I'm like,
[01:20:54]
oh, well, what has changed since the last version?
[01:20:58]
Well, let me open up my laptop and run Elm diff in a terminal.
[01:21:04]
Yeah, that is very useful, but it's not always a great experience.
[01:21:08]
I'm not always on a computer.
[01:21:10]
So another thing that is not always clear cut is like,
[01:21:14]
what belongs in the package docs and what belongs in some external place,
[01:21:19]
either the readme, a separate document in GitHub, or an external site?
[01:21:26]
Yeah.
[01:21:28]
Do you ever find reason for having something that's not included in the readme or the Elm package docs?
[01:21:35]
Yeah. So Elm review, for instance, has...
[01:21:40]
I say for instance, but all Elm packages are Elm review related.
[01:21:46]
Maybe one day I will have something else, but for now, they're all Elm review related.
[01:21:50]
Wow.
[01:21:52]
After so many years of work, still only Elm review.
[01:21:56]
Well, it's focus.
[01:21:58]
Yeah, I guess. Well, and packages that I'm not maintaining.
[01:22:03]
So there is a document, for instance, for how to integrate Elm review into other places like IDs or bots or something.
[01:22:13]
So there's a documentation that describes how the CLI outputs some format that can be understood by computers.
[01:22:22]
And that is not relevant to the API.
[01:22:27]
So the Elm review package, the Elm package is meant to be used by people who write rules or who configure their Elm review configuration.
[01:22:39]
Everything else makes little sense.
[01:22:43]
There's still like all the how to get started, how to configure, how to install Elm review,
[01:22:49]
which is like an additional section because there's some NPM involved.
[01:22:54]
But yeah, I think there are some cases where you will need other things.
[01:22:58]
The main one that I can think of, and that does not necessarily fit the Elm package website very well, is a guide.
[01:23:07]
And that's something you hear sometimes as well on the Elm Slack, is that people see the Elm guide and then they wonder,
[01:23:16]
oh, well, how do I learn more or how do I know which functions exist?
[01:23:22]
And we kind of assume that they went to the package website and look at Elm core or they looked at other packages
[01:23:30]
and then know how to read that package website, which is a given once you've got some experience with it.
[01:23:37]
But like sometimes you want to know about the About tab or About page on a package and that has some relevant information.
[01:23:47]
But if you haven't browsed around, then you don't know about it.
[01:23:53]
So yeah, having like the Elm package websites with all the API plus a way to write a guide, that would be pretty nice.
[01:24:04]
So for instance, for Elm review, there's a lot of things that I try to teach that are not necessarily related to the API.
[01:24:12]
And that's why my documentation is really long.
[01:24:17]
Can you think of an example? Like would it be conceptually how an Elm review, how it traverses things with visitors or something like that?
[01:24:25]
Potentially, yeah, that's an implementation detail that would be worth explaining somewhere.
[01:24:31]
So for instance, if you want to explain like performance considerations, like you should use this function this way and not this way,
[01:24:41]
or you should have this architecture, then if that doesn't fit specifically with one function, then or in one module,
[01:24:50]
then it's a bit hard to know where to place it.
[01:24:54]
Also, just like guidelines on how to make great rules is at the beginning of the review the rule module, which is the main one.
[01:25:04]
But like it could be its own page, right? And also, for instance, like if you have a guide, then you can actually do a tutorial,
[01:25:13]
which I kind of try to do. And this is kind of why I say like, write your own story, because I'm in a way making a tutorial,
[01:25:21]
but maybe the way that the docs have rendered, it doesn't always make for the greatest experience.
[01:25:29]
But if I did not have to write all the API in the same page, then I would write it differently. And I would probably.
[01:25:36]
Yeah, I like the way you're framing that. I mean, I think like the example of performance tuning, a review rule or something like that is,
[01:25:46]
in that case, it gets to the point you were making earlier about who's the audience.
[01:25:51]
And, you know, the audience for very low level details of some JSON format of something is different than the audience of
[01:25:58]
how do I write a review rule? Maybe I want to make sure I'm using this internal API in our application in a particular way.
[01:26:08]
Well, I don't really care about performance, these performance considerations or this low level JSON format right now.
[01:26:16]
So it's a different audience. And you don't want to lump all those together. It's going to be very confusing.
[01:26:23]
I think maybe if the package websites just picked up on like all the markdown files in a documentation folder or something like that,
[01:26:33]
or something that is explicitly defined in the Elm JSON file, that could work very well.
[01:26:39]
Yeah, George Borges has talked about this idea with, you know, Elmbook and his inspiration from the Elixir documentation,
[01:26:48]
where they have both API documentation and sort of guides or markdown pages side by side.
[01:26:56]
So, yeah, I think you're right that there are certainly cases.
[01:27:01]
I mean, like you mentioned this example of, you know, Elm browser and then the Elm architecture in the Elm guide, right?
[01:27:09]
Like a user might go to the Elm browser docs or some core package and expect a guide, but actually that lives somewhere else.
[01:27:21]
But that does make sense. Like it would be too much for the scope of it to introduce the Elm programming language and the Elm architecture
[01:27:29]
all in the inline module docs. And it doesn't give you enough granularity.
[01:27:34]
So in that case, having these conceptual overviews doesn't fit there. Also tutorials like you might have a mini tutorial,
[01:27:42]
but you don't want to have a very ambitious tutorial that requires a lot of setup and a lot of steps and a lot of do it yourself exercises inline in your module docs.
[01:27:53]
It's just they should be very narrowly scoped. So something like that definitely belongs in an external tool,
[01:28:00]
which some package authors have external sites. Elm pages has an external doc site.
[01:28:06]
And, you know, it covers things like just a conceptual overview of Elm pages because the scope of it is very large and it wouldn't fit neatly in one module documentation page
[01:28:19]
or things that happen around generated code. What module do you put that in? It's describing a set of generated modules.
[01:28:28]
So there's like a file structure document that talks about navigating the file structure of an Elm pages application and what sort of modules are generated from that.
[01:28:39]
You know, certain things about the philosophy and the architecture and diagrams for the architecture, the adapter API,
[01:28:47]
which allows you to adapt to different deployment and hosting platforms.
[01:28:52]
So, yeah, so there's definitely I mean, my rule of thumb is if something fits neatly in a modules docs, put it there.
[01:29:01]
For example, back end task, I could put it in a separate, you know, it almost wants to be part of the Elm pages docs for Elm-pages.com slash docs.
[01:29:13]
Like I almost want it in the listing there, but it can fit in a module doc. So I put it there instead.
[01:29:20]
There's also like you can have a website, like a custom website where it says blazingly fast, you know, the obvious catchphrase,
[01:29:29]
where you can just make it look good. Just marketing wise, the package's website is not super handsome.
[01:29:41]
Like it's a good looking website. It's a very simple website, but you're not putting like marketing wise,
[01:29:48]
the JavaScript people will tell you, hey, this is shit. Like my Vite package looks the same as the Parcel package.
[01:29:58]
How can I make it obvious that this one is better without being able to choose my colors for my package documentation page?
[01:30:09]
So I think there's also a case where you want to have a dedicated website. I'm not sure how much overlap there is.
[01:30:19]
And when you want to have a additional, when you want to have a website and package documentation and a guide,
[01:30:28]
and how you mix and match them together. So I'm kind of used to have on the package websites.
[01:30:35]
And therefore, if new opportunities open up to me, like having the ability to write a guide,
[01:30:43]
I'm not sure how I will write the documentation yet.
[01:30:46]
There are definitely certain things that fit better in a custom site. Like you said, I mean, having more control over the styling,
[01:30:53]
but also if you want to have a showcase or certain community things like in the Elm Pages site, I have something that lets you submit.
[01:31:01]
There's a button to submit to the showcase. It uses Airtable and it pulls data from that API live or, you know, a blog.
[01:31:11]
Should you have a blog hosted on the Elm Package site? Probably not.
[01:31:14]
Yeah. You also maybe want to have like release notes that are displayed nicely, news, blogs.
[01:31:23]
And yeah, as you say, like things that are not relevant to the API, but that are relevant to the package,
[01:31:32]
like how many people use this, who is sponsoring this package or yeah, things like that.
[01:31:39]
Right. Yeah. Yeah. And in general, there are all these different rich formats. I think they all serve their needs.
[01:31:46]
Having a custom blog serves its need. Having Elm Package Docs does its job extremely well.
[01:31:52]
And having them both is really useful. Things like GitHub discussions, GitHub issues, poll requests, conference talks, podcast episodes.
[01:32:03]
All these things are great sources of information in different formats that serve different purposes.
[01:32:09]
A GitHub discussion is a great place to showcase ideas and community projects and get feedback on things and discuss specing things out
[01:32:19]
or making decisions or documenting history about something. Package Docs are not a good place for that.
[01:32:25]
But if there's some quirky thing that people are frequently asking about, go ahead and link to that GitHub discussion thread
[01:32:34]
that talks about the history and the spec and why that decision was made.
[01:32:38]
So I think this model of linking out to a lot of different resources, keeping things very concise and focused on one purpose.
[01:32:47]
But then if you're on this page and you're looking for something more, let me throw some links your way just in case.
[01:32:54]
That's hugely valuable. I don't think you can understate the power of just...
[01:33:00]
And even just linking to in between different module pages in an Elm Package is huge, I think.
[01:33:08]
Another great thing is that whenever you have a function, it has a type annotation and the type annotation has references, different types.
[01:33:19]
And whenever you have a type that is defined in your package, that becomes a link.
[01:33:25]
So you can click on it and now you can see where that was defined. And that is very valuable.
[01:33:31]
So if you can add more links for things that are not done that way, that's very valuable. I agree.
[01:33:40]
Yeah. Also, on a related note, I think we all have the curse of knowledge, especially as authors of packages,
[01:33:47]
where we have trouble understanding what it would be like navigating something because we know those things.
[01:33:56]
So it's hard to revert back to a state of not knowing those things and understand, not to mention different things will be confusing for different users,
[01:34:07]
coming from different avenues and different ways of thinking about things.
[01:34:10]
But I think it's a really good practice to get in the habit of understanding what assumptions you're making.
[01:34:19]
And there are certain habits that I've tried to build personally, where I'll try to notice when I'm making assumptions.
[01:34:25]
So like one easy one is an acronym. If you're mentioning an acronym, just spell it out.
[01:34:32]
Just say what the acronym stands for. You can use the acronym, but introduce at least what it stands for first.
[01:34:39]
Yeah. And you can even like if it's a concept like the CAP theorem, then you can link to a Wikipedia page or something that talks about that.
[01:34:51]
Or a blog post that has more information and simplifies, vulgarizes the concept.
[01:34:57]
Because sometimes Wikipedia is not very, very nice, especially for mathematical things.
[01:35:04]
Link to the Monad page.
[01:35:07]
Right, right. Yeah, but exactly. Any terms like that, that might require some specific domain knowledge, just go ahead and link to it.
[01:35:16]
You know, if you're talking about a type from a package, link to that external Elm package or NPM package or whatever it might be.
[01:35:26]
I also find that sometimes, like when I'm writing out docs, I will say, if I'm using the word it or that or this,
[01:35:38]
sometimes I'm like, wait a minute, are they going to know what I'm referring to?
[01:35:42]
Because I just covered a lot of things and sometimes instead of it, I'll say, you know, the backend task type.
[01:35:50]
And so now it's like, OK, backend tasks allow you to do that.
[01:35:55]
It gives you, you know, I'll just say backend task also, you know, because it's very subtle.
[01:36:02]
But I think that people can get tripped up on small details like this.
[01:36:07]
So be very explicit, show all of your imports, show your work, link to things, define your terms, just like go overboard with those things.
[01:36:16]
Yeah. Also, if you re-mention the backend task, you can make it a link.
[01:36:22]
So people don't have to go back to the very top of the page to find the link to backend task.
[01:36:27]
So that's also quite nice. And also like try to avoid words like just or simple or like they make sense in some cases.
[01:36:36]
But you have to be careful about those. Like what seems simple to you or easy to you is not necessarily the case for other people.
[01:36:43]
Although simple is objective, but you need to have watched Rich Hickey's talk about that.
[01:36:50]
Right. Yeah. I think also being straightforward and, you know, not saying like necessarily this is the best way to do this,
[01:37:03]
but saying these are the decisions. I think it's really good to be clear and explicit.
[01:37:10]
These are decisions. I believe these are pros of these, this set of decisions.
[01:37:15]
Perhaps here are some cons about this set of decisions, but these are the decisions. This is the philosophy.
[01:37:20]
I think we talked about this in our Elm Radio episode of how and when to write an Elm package.
[01:37:26]
But, you know, I think it's really valuable to just be up front with people and tell them because you can't you can't do everything.
[01:37:35]
You can't make every you know, I'll make every single trade off out that no, like a trade off.
[01:37:41]
You have to trade something. Which one do you want to choose? So just don't mince words.
[01:37:47]
Go make some bold decisions because and allow for different approaches to coexist that make different versions of those trade offs.
[01:37:58]
And so you don't have to take that responsibility of solving every problem.
[01:38:03]
Yeah. Or try to find a novel way that solves everything in a nice way, which is usually what we end up doing in the Elm world somehow.
[01:38:12]
Often with success and I guess the success, the failures are not published or.
[01:38:18]
It's true. It's true. There's a bias there. Definitely.
[01:38:22]
Yeah, it depends on the example. I guess like Elm Review does a great job sort of making the best of both worlds.
[01:38:30]
Whereas something like Elm GraphQL inherently there's a decision.
[01:38:34]
Do you have a query builder style or a generator style that spits out code for a specific GraphQL query?
[01:38:42]
Those are trade offs that there's you just have to pick one and say, we think there are merits to this approach,
[01:38:50]
but we can't make a perfect solution that makes everybody happy because there are trade offs.
[01:38:57]
Well, anything else we should point people to for writing great docs?
[01:39:02]
I think we've already given a lot of great tools and links, so you can see those in the show notes.
[01:39:08]
Try to do your best. Try to make it to make it understandable by people.
[01:39:14]
Ask for feedback and iterate like you're not going to get things right the first time you're going to have typos.
[01:39:21]
You can have things that are not clear and that's fine.
[01:39:24]
Just one thing. Try to avoid breaking changes as much as possible, but it's not a big deal either.
[01:39:31]
Yeah, and listen to your users.
[01:39:33]
I skimmed a little bit through a book that I had heard about called Docs for Developers,
[01:39:39]
and I quite liked what I read.
[01:39:41]
It was in a nice skimmable format, and they even talked about the importance of being skimmable,
[01:39:47]
which is near and dear to my heart as a reader of some portion of documentation.
[01:39:54]
I would definitely recommend checking that out.
[01:39:57]
Yeah, but you don't know why it's important for things to be skimmable because you've skimmed that, right?
[01:40:02]
That's right.
[01:40:03]
Okay, yeah, sure. Just want to be clear about that.
[01:40:07]
All right.
[01:40:08]
All right. Well, Jeroen, until next time.
[01:40:11]
♪♪♪