# Do you have a giant \`Types\` module in your projects?

**URL:** <https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619>\
**Category:** Uncategorized\
**Created:** [June 1, 2022, 11:50am UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619 "2022-06-01T11:50:56Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon58422685](https://avatars.discourse-cdn.com/v4/letter/a/67e7ee/32.png) [@anon58422685](https://discourse.haskell.org/u/anon58422685)\
**Post date:** [June 1, 2022, 11:50am UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619/1 "2022-06-01T11:50:56Z")

</div>

So, there is a monolithic back end application I and some friends are working on. It has a module `Types` with 116 `data` definitions _(and counting)_ that everything else depends upon. A smallest change, like say adding a `Show` instance, entails recompilation that takes several minutes, with all the generic `instance FromJSON` definitions and such.

I am starting to question if this is a best practice.

In my recent additions to the code base, I prefer to write the `data` definitions at the same module where I need them so that they do not burden the compilation process. However, this is also not optimal: often a client module only needs the types, not the logic, and it is comfortable to import all the types at once.

So, if we decide to always keep types separate from logic, then there are several ways to organize the types:

1. A single module `Types` that everything else depends upon.

2. To every module `Logicᵢ`, a module `Logicᵢ.Types`.

3. Split the module `Types` into `Types.Logic₁`, `Types.Logic₂`, then import everything into `Types`.

4. More radically, have `Types` split a module for each type, like `Types.Type₁`, `Types.Type₂` and so on.

Another consideration is that, in the future, we might start to generate some types from the data base schema and the HTTP API specification automatically, and some combination of approaches 3 and 4 seems to be the easiest to automate.

What is the advisable way forward?

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [June 1, 2022, 12:01pm UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619/2 "2022-06-01T12:01:46Z")

</div>

I remember this blog post: [Haskell for all: Module organization guidelines for Haskell projects](https://www.haskellforall.com/2021/05/module-organization-guidelines-for.html). ~~It doesn’t really mention compile times~~ (it does actually), but it does discourage the use of one big Types module.

---

<div class="post-metadata">

**Author:** ![f-a](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/f-a/32/2740_2.png) [@f-a](https://discourse.haskell.org/u/f-a)\
**Post date:** [June 1, 2022, 12:23pm UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619/3 "2022-06-01T12:23:53Z")

</div>

I think everyone starts with a “vertical” organisation, (a `Syntax` module, a `Parsing` module, etc.).

Eventually as your program grows bigger you can encounter circular dependencies. Now you have the option to:

- use `.hs-boot` files; or
- use `Syntax.Primitive` / `Syntax.Type` modules; or
- use one big `Types` module.

With the first you have two files with overlapping information; with the second you are splitting “related functionality” among different files; the third one a type salad.

---

<div class="post-metadata">

**Author:** ![Kleidukos](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/kleidukos/32/1213_2.png) [@Kleidukos](https://discourse.haskell.org/u/Kleidukos)\
**Post date:** [June 1, 2022, 12:57pm UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619/4 "2022-06-01T12:57:02Z")

</div>

Organise your application around the business concepts that it handles, and keep the types close to the functions that use them.

Do avoid a monolithic Types module, even if it only re-exports. This will mess the compilation graph of your project and create a bottleneck to parallel compilation.

---

<div class="post-metadata">

**Author:** ![jaspervdj](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaspervdj/32/586_2.png) [@jaspervdj](https://discourse.haskell.org/u/jaspervdj)\
**Post date:** [June 1, 2022, 8:21pm UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619/5 "2022-06-01T20:21:53Z")

</div>

Having a huge `Types.hs` module is definitely a bit of an antipattern, but it’s not something I worry about when I just want to get something working. So I do usually end up with something like that in the initial phases, but Haskell is easy enough to refactor once I want to clean it up a bit later.

---

<div class="post-metadata">

**Author:** ![taylorfausak](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/taylorfausak/32/54_2.png) [@taylorfausak](https://discourse.haskell.org/u/taylorfausak)\
**Post date:** [June 2, 2022, 12:41am UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619/6 "2022-06-02T00:41:02Z")

</div>

I know that the conventional wisdom is to organize your project by what things do rather than what they are. However I tend to organize my projects with each type in its own module, all under the `MyProject.Type.*` namespace. That has worked well for me in a variety of situations. I haven’t run into many circular dependencies, and when I do they are often trivially solved by introducing a type variable. A plus side of organizing things this way is that the build is very parallel and recompiles after changes are usually very quick.

---

<div class="post-metadata">

**Author:** ![wiz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/wiz/32/2408_2.png) [@wiz](https://discourse.haskell.org/u/wiz)\
**Post date:** [June 2, 2022, 7:47am UTC](https://discourse.haskell.org/t/do-you-have-a-giant-types-module-in-your-projects/4619/7 "2022-06-02T07:47:07Z")

</div>

I acquired the same habit at some time.  
I tend to lay out modules around one central type and its related instances, functions etc.  
Mutually-recursive types can be a problem, but may be they’re just a subpart of some other domain and really should be placed together as supporting types for that domain.

But, please, **please** , for the love of whatever gods may be looking upon us, don’t name _all_ your types `T` and constructors `C` 🙏  
Haskell is not ML, we don’t have necessary support for this pattern.
