Renaming the root folder from `lib` to `app` -- is this a bad convention?

The standard project structure is something like this:

~/
  lib/
    app/
      data/
      service/
    web/
       controllers/
       endpoint.ex
    application.ex
  test/

I’d like to rename the top directory to app instead of lib – to me it just makes sense that the top level folder is the application, and lib (library modules) are underneath it.

The Elixir community seems opinionated about this, so I wanted to start a discussion about it. What are some arguments against doing this?

What do you gain from this, technically? You should be able to achieve this by updating compiler paths in mix.exs but you’ll be fighting the conventions of most Elixir-aware tooling as well as distracting or alienating any collaborators who have done Elixir work using a standard project structure.

If it doesn’t inform the way you name or organize your modules I wouldn’t buck this particular convention. It may be more comfortable for you individually but it has drawbacks elsewhere. This is especially true if you ever migrate to an umbrella structure, because then you’d have paths like apps/foo/app/lib/foo.ex. (Admittedly umbrella projects are not universally beloved at all, I have my own personal disillusionment with them, I’m just raising it as a point of friction to consider.)

3 Likes

Since “application” is an important thing in erlang world, src would be better name if we really want to rename it away from lib.

… actually that’s what erlang projects do and that’s why elixir choose lib.

1 Like

lib just seems like an odd word choice, esp since it contains the bulk of application logic, as opposed to a library

This is something I agree with too.

In any other language or framework I’ve used in the past, my application typically lived in either an app directory or a directory that was named after the app.

Then lib was reserved for actual library code. AKA something that’s not tied into your app’s business logic and could in theory be generic and used in another project. Typically I’d have that code sit in lib until it gets mature enough to be open sourced and moved into a dedicated external package.

I’ve always had that struggle with Elixir and Phoenix. Because placing generic non-business logic code in contexts never made sense but there’s really no other places for it to go unless you start breaking conventions.

I don’t understand this remark as my immediate reaction is: “just don’t put your generic code in the files and modules that represent your context”.

A context is a concept of encapsulating business logic behind well defined interfaces and preventing to leak implementation details into other layers. This is orthogonal to the lib directory, which is just where you put your source code. If you renamed it to src would it make a difference? Your code layout would look exactly the same under src as lib.

Some of the source code under lib may be part of your application logic. Some source code under lib may be generic code. Some source code may represent your contexts. I don’t see how putting generic code under lib mixes them with contexts unless you intentionally put generic code in the modules that are representing your contexts.

1 Like

The point at issue is the naming of the folder.

Some of the source code under lib may be part of your application logic. Some source code under lib may be generic code. Some source code may represent your contexts

This is the source of the issue. lib , IMO, should be for library code. That is, code that is generic. Contexts and the like are separate, semantically and functionally, and so should be separate.

Or should it? There is a cost with breaking with convention. I started this thread because I don’t like have a lib folder containing application code.

This is where the problem lies. Suddenly you have your app’s 15 contexts but there’s also 10 generic libraries all sitting in the same lib/hello directory. It makes the code base very unorganized feeling. I can’t glance at that and know which files are generic or not.

1 Like

I agree that lib perhaps sends the wrong signals. But in the end it is just a name. It doesn’t change the important part what is goes into the directory.

It would be interesting to try to see how code generators and such (mostly phoenix I guess) would deal with renaming lib to app for example.

Howabout

lib/common/myqueue/
lib/common/myother/
lib/yourapp/somecontext/
lib/yourapp_web/...

? or perhaps (if you want to contain everything under yourapp namespace)

lib/yourapp/common/myqueue
lib/yourapp/common/myother
lib/yourapp/contexts/
lib/yourapp_web/

I would be interested in what framework, languages you are comparing with as non of the other I work with does things differently than elixir.

If you plan on ever working with other people, I’d suggest against doing something like this. Code needs to ultimately follow a pattern so collaborators can have the lowest possible cognitive load when reading it, breaking a core convention like this because of a personal opinion is not worth it on the long run.

4 Likes

I develop for Android, iOS, Erlang, and Elixir, and I could not care less about the name of the source code folder. In Android projects, you put your Kotlin code under the “java”-subdirectory. This is how bad as it sometimes get. If you rename “lib” to “src”, you would then probably complain that your JS files live somewhere else.

1 Like

Agreed, but in theory descriptive naming would actually help collaborators find things easier.

1 Like

With Rails, you have app/ and lib/ living at the same directory depth. Your app’s code goes in app and your generic library code goes in lib.

With Flask, there’s no conventions or special behavior around a lib/ directory so you can do anything you want. I usually roll with a hello/, lib/ approach where both dirs are living at the same depth. It gives a similar separation as Rails and in Python it’s a convention to name your app’s folder the name of your project, which is why I didn’t pick “app” for it.

In this Elixir case, app vs lib as a name isn’t my main concern. It’s not having a clean and well defined area to put library / generic code. Your first “how about” example seems reasonable but it feels like we have to force a 2nd name to describe what a library is without using lib/.

The clean way imo is not having library code in your application, but like third party libraries in dependencies. Sadly this is often neglected (by myself as well) for the overhead it generates. Also there’s nothing stopping you from separating code within lib/. Just like phoenix does myapp and myapp_web you can have myapp_lib or whatever. In one of my projects I have myapp_auxiliary, which holds all the domain unrelated stuff integrating with dependencies I have (potentially even temporarily).

1 Like

Yeah because in practice that library code usually follows the path of being inlined somewhere, then pulled out into a generic function or module and then maybe if deemed useful over time extracted out into a third party library that may or may not be open sourced.

If you skip the middle step, as you mentioned, it adds a massive burden to your development work flow and it could also lead to premature abstraction and poor library design choices. It’s why you can’t often “invent” a good library. It needs to be extracted from a real world project, and the pipeline to get there is critically important.

Do you namespace those lib modules as MyAppLib.CountryCodes or CountryCodes?

The first one, mostly for preventing the slim possibility of collision with proper dependencies.

Previously Phoenix did put things in the “app” directory and many complained that “Phoenix was leading people away from Elixir conventions” or that “building a Phoenix application should not be different than any other Elixir codebase”.

It is one of the discussions that could go in loops forever, especially as it is an easy topic to get sidetracked with. So my recommendation would be to stick with the current conventions. If you really want to change it, do it in your mix.exs.

Once you choose a directory, you can do whatever structure you want inside that directory. It doesn’t have to be only my_app and my_app_web, feel free to create directories for other needs. I personally go with similar approach to @LostKobrakai (my_app, my_app_lib, my_app_web, etc).

9 Likes

I don’t care if the folder is named lib or app. It could be named “stuff” honestly, but that would have more people dissatisfied. What I do care about is that there is a strong convention that is consistently used. When I pick up a project I can immediately find my way. The lib name is probably not perfect but it absolutely works well in my book.

7 Likes