# Experience report after finishing a (reasonably substantial) Julia project in 2024

**URL:** <https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148>\
**Category:** Community\
**Created:** [April 18, 2024, 2:17pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148 "2024-04-18T14:17:29Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 18, 2024, 7:15pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/44 "2024-04-18T19:15:27Z")

</div>

I use Pluto extensively in my research projects, but in this case it doesn’t scale.

I am thinking about going the OCaml way and abstract using modules:

```julia
module TypeA
  struct T ... end
  method_a(a::T) = ...
end
...
import TypeA
...
a = TypeA.T(a)
TypeA.method_a(a)
...

```

This is supposed to allow me to modify `T` and reload the whole module. I haven’t done it in practice.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [April 18, 2024, 8:06pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/45 "2024-04-18T20:06:33Z")

</div>

> [@rongcuid](#):
>
> Plus I can’t do italics + bold.

That’s done with `font = :bold_italic` for the default font face, mentioned here [Fonts · Makie](https://docs.makie.org/stable/explanations/fonts/#symbol) (you have to pick font faces, not layer bold + italic, because many fonts have multiple weights anyway).

> [@rongcuid](#):
>
> _Maybe_ if there’s an intermediate level API which allows me to, say, draw each character directly

That exists but isn’t public, it’s called `GlyphCollection` and can be passed to `text` [Makie.jl/src/types.jl at f51eb527806e184690b577e17e630e9c9c521cb9 · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/blob/f51eb527806e184690b577e17e630e9c9c521cb9/src/types.jl#L374)

And I’m not sure about the line spacing problem you mention, in principle that should be adjustable. Although could be that rich text doesn’t do this right now, I don’t remember

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [April 18, 2024, 8:14pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/46 "2024-04-18T20:14:54Z")

</div>

> [@rongcuid](#):
>
> in this case it doesn’t scale

Hence the suggestion to integrate Pluto into your workflow at the prototyping stage of a module or type, rather than moving your entire project into a notebook. Place `import Pkg; Pkg.activate(Base.current_project())` at the top of the notebook to make it run in the environment you’re developing in such that you can easily prototype on top of existing project code. And with `Pluto.run(auto_reload_from_file=true)`, you don’t even have to leave your editor, Pluto can just be a monitor for the state of your code.

Just throwing this out as one possible way of working around the struct redefinition limitation. Of course, you may find that other workarounds suit you better, such as your suggestion of wrapping a module around each new type.

---

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 18, 2024, 8:16pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/47 "2024-04-18T20:16:26Z")

</div>

I didn’t make the connection between the rich text documentation under `text()` and the fonts documentation.

I totally didn’t see `GlyphCollections` when I dug through Makie’s code to look at whether I could work around the rich text issues. I searched for `rich` (which was where the problem was reported), landed on [Makie.jl/src/basic\_recipes/text.jl at f51eb527806e184690b577e17e630e9c9c521cb9 · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/blob/f51eb527806e184690b577e17e630e9c9c521cb9/src/basic_recipes/text.jl#L291), and then had completely zero idea where the entry point is by looking at this piece of code.

You see, every single parameter of every type is written in, you guess it, `(args...; kwargs...)`, so I had a lot of trouble navigating Makie’s code base. Now that you mention the existence of `GlyphCollection`, I found the entry point (`plot!`, I suppose) immediately at the top of the file lol.

---

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 18, 2024, 8:17pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/48 "2024-04-18T20:17:17Z")

</div>

Ok. I don’t remember Pluto could do it, but maybe I had memories of old versions.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 18, 2024, 8:21pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/49 "2024-04-18T20:21:12Z")

</div>

I’ll address one of your sections as a sort of jumping-off point to responding to the spirit of the whole.

> [@rongcuid](#):
>
> ## Enums
> 
> I used the `@enum` macros a few times in my code.
> 
> Don’t use them, really. They are not namespaced, there’s no multi dispatch, and there’s no pattern match. Abstract classes are more powerful.

Julia enums are much like C enums: they’re numbers which you can refer to by name. They are nothing like Rust or Java enums at all, so if you expect them to be, you’re going to have a bad time.

Julia has one namespacing mechanism: modules. Anything in the top scope of a given module shares a single namespace, enums included. For enums, I tend to do what we do in C, and use a prefix, so a VM I’m working on, the enums for instructions are all `IAny`, `IReturn`, and so on.

Is that ideal? It depends on what you’re working on, I suppose, or what you’re used to, or both. If you want a namespaced enum, EnumX.jl provides this. It uses a module, in fact.

You can use enums for dispatch, although how to do it isn’t at all obvious. Using the example enum from the documentation, here’s how.

```julia
julia> @enum Fruit apple=1 orange=2 kiwi=3

julia> f(::Val{apple}) = "I'm an apple"
f (generic function with 1 method)

julia> f(::Val{orange}) = "I'm an orange"
f (generic function with 2 methods)

julia> f(::Val{kiwi}) = "I'm a kiwi"
f (generic function with 3 methods)

julia> f(fruit::Fruit) = f(Val(fruit))
f (generic function with 4 methods)

julia> f(apple)
"I'm an apple"

julia> f(kiwi)
"I'm a kiwi"

```

If you’re using enums in the common fashion, where they get written as constants, directly into the text file, then this will be fast. If the enums are being passed around in variables, you’re better off dispatching in a different way. Using a collection of zero-width subtypes is another option, and it might be a better one, depending on what you’re doing.

At least, I _think_ that using an enum by name is treated like a constant, not a variable, by the compiler. It’s difficult to be sure of these things.

Pattern matching: there are a few packages, the obvious one is named Match.jl, and it works fine with enums. It is not exhaustive, you won’t get an error if you don’t match all branches. That’s pretty normal with Julia, but for enums specifically, which can’t be extended, it would be possible to write an exhaustive pattern-matching macro which threw an error if you didn’t handle all cases. I’m not aware of any, however.

The point of my answer here, however, is that this is a pervasive problem with the ecosystem. How is a beginner supposed to know you can dispatch on enums using the Val pattern? There are breadcrumbs in the manual, but that’s it.

I think it’s great that someone who wants namespaced enums can write a macro and make it a package, and that there several competing implementations of pattern matching based on macros as well. I think less things should be in stdlib, not more.

But discoverability is really rather bad. And it isn’t great that something as basic as pattern matching doesn’t have a clear winner which everyone uses.

This is a combination of the size of the user base and the essential complexity of the language. The only way out is much better supporting documentation, and more of it, and the way to get that is to keep growing and stimulate enthusiasm in the user base. There aren’t easy answers here.

Meanwhile, getting to know Julia requires some determination to trawl through juliahub and old Discourse threads. It is simply harder to figure things out than it is in many other languages, and that needs to change.

---

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 18, 2024, 8:36pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/50 "2024-04-18T20:36:01Z")

</div>

I used prefixes:

```julia
@enum SkillRarity begin
    SkillNormal
    SkillRare
    SkillEvolved
    SkillSpecial
end

```

And didn’t find out there was no pattern matching until I implemented 20 skills in ~800 LoC, finished the whole simulation, and finally needed these enums for visualization. So in the future I will treat them like C enums.

> [@mnemnion](#):
>
> The point of my answer here, however, is that this is a pervasive problem with the ecosystem. How is a beginner supposed to know you can dispatch on enums using the Val pattern? There are breadcrumbs in the manual, but that’s it.

This is my first time seeing a `Val` pattern. I have thought about if it could be done because some other lisps could do it, but I never found it despite actively searching for it in the official documentation, especially through the methods and dispatching docs.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [April 18, 2024, 8:41pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/51 "2024-04-18T20:41:55Z")

</div>

> [@brianguenter](#):
>
> Can we add a prominent link on the Julia language home page to [ModernJuliaWorkflows](https://modernjuliaworkflows.github.io/)? Just like the Rust and Go examples? And then do our best as a community improve it and keep it to date, as we do with the rest of the Julia documentation?

Co-creator of [ModernJuliaWorkflows](https://modernjuliaworkflows.github.io/) here: contributions are always welcome!  
The initial goal was to contribute the posts to the Julia blog, but instead maybe our website deserves a life of its own? I could definitely see it becoming a less formal, more hand-holding companion to the detailed documentation. Of course, putting a link to MoJuWo in the [important links](https://docs.julialang.org/en/v1/#man-important-links) section would make it seem more official than it is… but in Julia world there really isn’t such a thing as “official”, there is only “useful to the community”.  
If you’re wondering why all this stuff is not _already_ in the docs, see this previous discussion:

> [@Write documentation PRs not blog posts](https://discourse.julialang.org/t/write-documentation-prs-not-blog-posts/100942):
>
> I will start by saying I have read many useful blog posts and course notes that have been linked on this forum, and I greatly appreciate the effort that goes into making them. The problem is they are not discoverable. It is my opinion that these guides would be much better served as a “Tutorial” or “Usage Guide” section in the official documentation for each package. I would like to have a discussion about that stance and what we can do to improve discoverability of fundamental knowledge for new…

---

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 18, 2024, 8:45pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/52 "2024-04-18T20:45:00Z")

</div>

`Val` is in fact, not in the documentation:

[https://docs.julialang.org/en/v1/manual/methods/](https://docs.julialang.org/en/v1/manual/methods/)

It’s there in the API:

[https://docs.julialang.org/en/v1/base/base/#Base.Val](https://docs.julialang.org/en/v1/base/base/#Base.Val)

However, I will never find it if I haven’t read the entire Base API documentation.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 18, 2024, 8:47pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/53 "2024-04-18T20:47:57Z")

</div>

> [@rongcuid](#):
>
> And didn’t find out there was no pattern matching until I implemented 20 skills in ~800 LoC, finished the whole simulation, and finally needed these enums for visualization. So in the future I will treat them like C enums.

Well, and that’s the thing: there _is_ pattern matching, but it uses Julia’s excellent metaprogramming facility, so it’s a library. Several, in fact. But everywhere else, it’s a core part of the language. This isn’t quite the dreaded [Lisp Curse](http://www.winestockwebdesign.com/Essays/Lisp_Curse.html), but it’s related.

> [@rongcuid](#):
>
> This is my first time seeing a `Val` pattern. I have thought about if it could be done because some other lisps could do it, but I never found it despite actively searching for it in the official documentation, especially through the methods and dispatching docs.

There is a section on [value types](https://docs.julialang.org/en/v1.10/manual/types/#%22Value-types%22), but it doesn’t connect them with enums in any way.

In larger languages you’d search for “Julia enums” and find a blog post called, like, “Julia enums: more than you ever wanted to know” which lays it all down on the table for you. That search does yield some interesting stuff, including a sum-types project SumTypes.jl, which I’d completely forgotten about, and uses the macro system to make Rust-style enum types.

But there isn’t an exhaustive treatise. It’s the size of the community, more than anything.

---

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 18, 2024, 8:51pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/54 "2024-04-18T20:51:25Z")

</div>

> [@mnemnion](#):
>
> There is a section on [value types](https://docs.julialang.org/en/v1.10/manual/types/#%22Value-types%22), but it doesn’t connect them with enums in any way.

Good note. I was looking at “Methods” page all that time.

I’ve came across `SumTypes.jl` in this project. I deemed it overkill at the time and thought nothing about it.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [April 18, 2024, 10:06pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/55 "2024-04-18T22:06:01Z")

</div>

You can get a certain level of pattern matching just by using dispatch and argument destructuring:

```julia
foo((x, )::Tuple{Any}) = x
foo((x, y)::Tuple{Any, Any}) = x, y
foo((; a)::NamedTuple) = a

```

```julia-repl
julia> foo((1, ))
1

julia> foo((1, 2))
(1, 2)

julia> foo((a=10, b=20))
10

```

(The type annotations for the arguments are necessary because otherwise the argument would be typed `Any` and each definition would overwrite the previous one.)

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [April 18, 2024, 10:22pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/56 "2024-04-18T22:22:16Z")

</div>

> [@rongcuid](#):
>
> Another problem is that when reading another person’s code, especially on GitHub or other places where an LSP is not available, it’s very difficult to find where a symbol is defined: if I am reading `b.jl`, anything there could be defined in `ModuleA.jl` or `a.jl`.

This doesn’t really help with reading other people’s code, but for your own code, it sounds like you might like my [ExplicitImports.jl](https://github.com/ericphanson/ExplicitImports.jl) package. It helps convert `using Foo` into `using Foo: x, y, z`, based on whatever names `x`, `y`, `z`, you are actually using in your code.

---

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 18, 2024, 10:36pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/57 "2024-04-18T22:36:58Z")

</div>

This is not good for research code, because I am refactoring so frequently that I cannot imagine myself maintaining not only an export list, but also an import list.

If Julia’s LSP is as good as rust-analyzer or IntelliJ Java, then we are talking.

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [April 18, 2024, 10:40pm UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/58 "2024-04-18T22:40:59Z")

</div>

Yeah, it is mostly useful once the code is stable, so you can convert to an explicit list at that point.

---

<div class="post-metadata">

**Author:** ![indymnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/indymnv/32/212594_2.png) [@indymnv](https://discourse.julialang.org/u/indymnv)\
**Post date:** [April 19, 2024, 12:34am UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/59 "2024-04-19T00:34:48Z")

</div>

Nothing to add, but just show appreciation for the nice article you wrote. Hope this kind of feedback can help to improve Julia.

---

<div class="post-metadata">

**Author:** ![liuyxpp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liuyxpp/32/9870_2.png) [@liuyxpp](https://discourse.julialang.org/u/liuyxpp)\
**Post date:** [April 19, 2024, 12:50am UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/60 "2024-04-19T00:50:57Z")

</div>

> [@rongcuid](#):
>
> Another problem is that when reading another person’s code, especially on GitHub or other places where an LSP is not available, it’s very difficult to find where a symbol is defined: if I am reading `b.jl`, anything there could be defined in `ModuleA.jl` or `a.jl`.
> 
> I’ll just straight up say that it’s worse that `#include` in C. In C, there’s at least forward declaration that allows me to break cycles without shuffling stuff between files. Unfortunately, Julia doesn’t have that.

I strongly agree with this. It is so painful to read other’s codes just in Github.

> [@rongcuid](#):
>
> Makie is very powerful and very fast (once warmed up), but not mature. I know it well enough to navigate its documentation, but when I started out I had no idea how to read its documentation. Especially problematic is all those `kwargs` used in its API, which require a lot of digging to figure out. I think its documentation needs some reorganization. It is, however, a very powerful library, allowing me to make very complex plots.

And this one is also frustrating for me.

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [April 19, 2024, 2:16am UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/61 "2024-04-19T02:16:47Z")

</div>

> [@rongcuid](#):
>
> Naming is hard [citation needed]. Let me reiterate: use `snake_case` for functions and `PascalCase` for types. Please don’t use `nocase`, even though the official docs recommend it.

Well, i _personally_ find that it is more convenient to mix different conventions, and julia makes that easy:

Dot case? no problem

```julia
julia> var"foo.bar"() = println("_ are overrated, use . instead")
foo.bar (generic function with 1 method)

julia> var"foo.bar"()
_ are overrated, use . instead

```

For people who prefer the `_` to be centered with the text:

```julia
julia> var"foo-bar"() = println("like snake_case, but aligned with the text")
foo-bar (generic function with 1 method)

julia> var"foo-bar"()
like snake_case, but aligned with the text

```

This is also a good one:

```julia
julia> var"foo bar"() = println("use ' ' as separator, because why not?")
foo bar (generic function with 1 method)

julia> var"foo bar"()
use ' ' as separator, because why not?

```

And my personal favorite, for when i started learning programming with CSS, and had to use double-dash naming convention for classes:

```julia
julia> var"my--very--long--variable--name" = nothing

```

---

<div class="post-metadata">

**Author:** ![rongcuid](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rongcuid/32/42911_2.png) [@rongcuid](https://discourse.julialang.org/u/rongcuid)\
**Post date:** [April 19, 2024, 3:15am UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/62 "2024-04-19T03:15:15Z")

</div>

You might have noticed already… but all of these are better than `nocase`.

```julia
myverylongvariablename = nothing

```

---

<div class="post-metadata">

**Author:** ![merlin](https://avatars.discourse-cdn.com/v4/letter/m/8baadc/32.png) [@merlin](https://discourse.julialang.org/u/merlin)\
**Post date:** [April 19, 2024, 3:28am UTC](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148/63 "2024-04-19T03:28:43Z")

</div>

Sevi’s next post has this. I think you mean something like poetry specifying dev dependencies for python packages, for example I use the `ptpython` repl in my development workflow in python but dont want this as part of my package dependency.

So yes, this is easy in the Julia REPL as Sevi’s post shows.

I like to keep several named ‘global’ environments, these are stored by default in the `~/.julia/environments` folder. For example mine looks like this:

```julia
ls -1 ~/.julia/environments/
__pluto_boot_v2_1.7.1
__pluto_boot_v2_1.9.2
data-work
stats-plotting
v1.0
v1.1
v1.4
v1.5
v1.6
v1.7
v1.8
v1.9

```

I handle dev dependency additions in my `startup.jl` file, but for me in REPL it would be:

```jl
] activate ~/.julia/environments/data-work
] add CSV TerminalPager Chain
julia> using CSV, TerminalPager, Chain
] activate .
julia> rand(100, 100) |> pager

```

I should also add that `CSV.jl` is extremely well supported.

[Previous page](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148.md?page=2)

[Next page](https://discourse.julialang.org/t/experience-report-after-finishing-a-reasonably-substantial-julia-project-in-2024/113148.md?page=4)
