# How to Organize Your Racket Library \[blog\]

**URL:** <https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717>\
**Category:** Show & Tell\
**Tags:** package, tips, documentation\
**Created:** [February 22, 2022, 9:55pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717 "2022-02-22T21:55:07Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [February 22, 2022, 9:55pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/1 "2022-02-22T21:55:08Z")

</div>

Fellow Racketeers in the trenches,

Here is a "how to" blog post on the commonly-used-yet-undocumented lib/test/doc approach to organizing your Racket library:

[How to Organize Your Racket Library](https://countvajhula.com/2022/02/22/how-to-organize-your-racket-library/)

It also includes some exercises to gain insight into packages and collections, and some discussion of other approaches.

I started this post several weeks ago after migrating my own library, [Qi](https://github.com/countvajhula/qi), to this structure. This was necessary to easily include third-party packages in the default "qi" distribution without introducing too many dependencies in the core functionality (and was suggested by Stephen De Gabrielle @spdegabrielle ). As it took me a while to set up, I felt I ought to blog about it to document it for the next person. Now that I've written the post, I understand why it wasn't documented to begin with. They say that fools rush in where angels fear to tread. Package management is a large and complex, and at times tedious topic. I've done my best to smooth over the tedium and get across the broad ideas in this context, while providing an explicit how-to. It was not easy, so I hope there will be some poor soul down the road who will consider my foolish efforts worthwhile 🙂

Last week Simon Schlee @simonls coincidentally [brought up this topic](https://racket.discourse.group/t/single-package-vs-multiple-lib-doc-test-convenience/693) for discussion on Discourse and it surfaced a lot of critical opinions on this approach. This was timely, and I think it complements the above post to provide a fuller picture of the various considerations on this complex subject, and I've linked to that topic from the post for greater visibility of these issues. Maybe with clarity will come needed reform.

Enjoy,  
-Sid

---

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [February 22, 2022, 11:08pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/2 "2022-02-22T23:08:14Z")

</div>

Highlights, for reference:

- Modules, collections, packages are like... files, folders, and archives
- The top level of your repo is hopeless as a package path
- Racket uses a global collection namespace
- Scribble docs and RackUnit tests all reside in this namespace along with your source files
- How to: lib/test/doc
- Includes a clunky migration strategy for when your existing libraries grow past a certain point
- Not everybody loves lib/test/doc and there's room for improvement

---

<div class="post-metadata">

**Author:** ![spdegabrielle](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/spdegabrielle/32/95_2.png) [@spdegabrielle](https://racket.discourse.group/u/spdegabrielle)\
**Post date:** [February 23, 2022, 9:12am UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/3 "2022-02-23T09:12:23Z")

</div>

I just heard about this [Modular Programming](https://felleisen.org/matthias/Thoughts/Modular_Programming.html)

---

<div class="post-metadata">

**Author:** ![simonls](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/simonls/32/170_2.png) [@simonls](https://racket.discourse.group/u/simonls)\
**Post date:** [February 23, 2022, 10:35am UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/4 "2022-02-23T10:35:08Z")

</div>

I like your post a lot, I think starting out with racket it would have helped me to get up to speed in understanding that package organization strategy.

The only thing I would like to state explicitly — _because I am unsure that it is conveyed 100% to the reader_ — is that `single-collection vs multi-collection` is orthogonal to `single-package vs multi-package`.

You can use them in any combination you like, e.g. in my [define-attributes](https://github.com/SimonLSchlee/define-attributes) package I use `single-collection` with `multiple-package`. Sometimes packages organized as `-lib/-doc/-test` use `(define collection 'multi)` in their combining package, even when the sub-packages all use a single collection. Starting out that gave me the impression that `multi-collection` was required to use `multi-package` but this is not true.

This is why I prefer it when the combining package uses something that matches the sub-packages, e.g. only uses `multi-collection` if at least one of the sub-packages does too.

I also wonder whether there should be a way to state within the `info.rkt` that this package has no collection / is an empty package that is strictly being used to combine the sub-packages, it feels wrong to specify a collection, when you never want it to contain something (in that particular package).  
Maybe `(define collection 'none)` could indicate that the package has no own collection and is only composed from its sub-packages.

---

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [February 23, 2022, 7:38pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/5 "2022-02-23T19:38:48Z")

</div>

Thanks, I'll incorporate this feedback into the post! I agree that `(define collection 'multi)` in the composite package is confusing and ambiguous. I also like the idea of adding a `none` option here to explicitly mark out a package as a composite -- I think in your `define-attributes` library if you adopted `none`, you would need to extract the tests and docs into a separate `define-attributes-support` package, right? Not that that's necessarily the right thing here but just to understand the implications of `none`.

---

<div class="post-metadata">

**Author:** ![simonls](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/simonls/32/170_2.png) [@simonls](https://racket.discourse.group/u/simonls)\
**Post date:** [February 23, 2022, 8:10pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/6 "2022-02-23T20:10:51Z")

</div>

Yes that would be the idea / result. In the `define-attributes` package I used the 2 package strategy suggested by @ryanc, so I think there using a single-collection declaration for both works well. (because neither is empty)  
But in general it may make sense to collect ideas for a while until some bigger vision emerges for how things could be improved in a coherent manner. So mostly I wanted to mention that idea, so that it isn't forgotten.

---

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [February 23, 2022, 8:22pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/7 "2022-02-23T20:22:12Z")

</div>

Btw, so as not to fragment the discussion on this topic, I would suggest for anyone reading, to post your comments on the [other topic](https://racket.discourse.group/t/single-package-vs-multiple-lib-doc-test-convenience/693) if it is more broadly about the lib/test/doc scheme or package management, and post here if it is feedback on the blog post specifically, e.g. if I should add anything / something is unclear / etc. Thanks!

---

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [February 23, 2022, 9:08pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/8 "2022-02-23T21:08:12Z")

</div>

I updated the post with your feedback @simonls , esp. [this section](https://countvajhula.com/2022/02/22/how-to-organize-your-racket-library/#ib-toc-anchor-14). I also added an FAQs section containing more about [single vs multi-collection packages](https://countvajhula.com/2022/02/22/how-to-organize-your-racket-library/#ib-toc-anchor-19).

---

<div class="post-metadata">

**Author:** ![scolobb](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/scolobb/32/108_2.png) [@scolobb](https://racket.discourse.group/u/scolobb)\
**Post date:** [February 25, 2022, 11:47pm UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/9 "2022-02-25T23:47:42Z")

</div>

A very useful and helpful post @countvajhula , thank you very much! I have long been troubled by the way in which Racket packages are structured, and your filesystem analogy finally fixed everything for me.

I realize now that the three-way (or multi-way) split and the global namespace is reminiscent of Linux filesystems with directories `bin/`, `share/`, `doc/`, `lib/`, etc.

---

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [February 26, 2022, 12:29am UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/10 "2022-02-26T00:29:11Z")

</div>

Thank you, I'm so glad to hear that 😃 The similarity to Linux organization is a very interesting observation.

---

<div class="post-metadata">

**Author:** ![slaymaker1907](https://avatars.discourse-cdn.com/v4/letter/s/59ef9b/32.png) [@slaymaker1907](https://racket.discourse.group/u/slaymaker1907)\
**Post date:** [February 26, 2022, 4:35am UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/11 "2022-02-26T04:35:57Z")

</div>

I had an idea while back to provide one version of a library, but provide backwards compatibility and versioning via submodules. Obviously prioritize not breaking things, but when breaks are necessary introduce a new submodule for the new version but leave previous version submodules in place. Additionally, don't try and leave previous versions' code pristine, adapt it as necessary to minimize duplication. The different submodules would exist solely for incompatible behaviors (so in many cases you would just import and provide common functions across various versions).

Racket submodules are neat in cases like this because all users will end up benefiting from many improvements/bug fixes without changing their code while the library developer can continue innovating on the API and introducing backwards incompatible changes. The main problem with this approach is that using submodules in Racket can be rather tedious. Additionally, since Racket made the very unfortunate decision to make "import \*" style imports the default, introducing new functions can be considered backwards incompatible.

---

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [February 26, 2022, 6:30am UTC](https://racket.discourse.group/t/how-to-organize-your-racket-library-blog/717/12 "2022-02-26T06:30:33Z")

</div>

Neat. I'm not sure I follow how this works exactly, but I bet it would be an interesting post if you chose to write it out in more detail with examples. I know folks have brought up handling backwards compatibility in the past, and there doesn't seem to be a standard way in the Racket community. Your scheme here sounds like one interesting way to do it.

Re: introducing new functions being backwards incompatible, do you know about [`version-case`](https://docs.racket-lang.org/version-case/index.html)? You could potentially use this to leave out the new definitions altogether depending on the version.
