kentan88

kentan88

Does my code/directory structure makes any sense?

Hi all, I’m relative new to Elixir/Phoenix here.

I’m trying to structure my code properly for ease of development. I’m also trying avoid bloated contexts, applying SRP to the best of my ability. Would really appreciate if I can get some feedback on my github repo here . Am I doing too much, too little or does it not make sense at all? Thanks in advance!

Most Liked

yordisprieto

yordisprieto

I see you are trying to follow Uncle Bob architecture. So I could share some personal experiences since I did most of the things you did in that project (all of them actually).

Also, worth to mention that this is an art and there are many ways, there is no right way to do it.

I will be using this package as an example, https://github.com/straw-hat-team/straw_hat_map

After doing what you did, I decided to move to DDD folder structure. The issue that your folder structure has, in my opinion, is that represents a programmer driven structure.

Entities

Originally I had it the way you have it right now, a mega folder (it will get big) with most of my schemas (entities), most of the time it was a pain having to go inside another folder all the time when the schema is only used on the a specific context (most of the time this will be the case if you do the DDD right).

What would happen when you have two schemas that would make sense to have the same name, but they are different depending on the context?

For example (for the sake of making a point), account from Accounts context and account from Sales context.

How will you structure your schemas folder now? You will keep creating folders or files (it will get big)

I am trying to make a more DDD approach to my folder structure. I no longer have any folder called schemas/entities/models,`.

I put a file in singular module and file name closer to the context that will be used, so you don’t have to jump between many folders.

Reduce the entropy of the files and folders.

Example: https://github.com/straw-hat-team/straw_hat_map/tree/master/lib/straw_hat_map/addresses

Queries

I would say, wait until you need actually to have a file with all the queries.

Initially, once again, I did what you did, but I had to go inside queries folder or file and to have to go back and forward between files that most likely will be touch at the same when you are working in that specific context.

I removed the concept of having queries inside a folder/file.

I put the queries on my context module and unless the file becomes problematic to manage I will no move it.

Most of those functions will become simply private functions on your context module; but once again, one less file that you need to open and paid attention to (wait until you have an issue).

Reduce the entropy and file management.

Worth to mention that most of those queries will be import in use cases that belong to the same context, so you will have to keep importing the same query module for all the services from a specific context.

Services

Once again since I did the same, I removed this concept of service.

My service is my context module, or I would call the module that implements the use cases https://github.com/straw-hat-team/straw_hat_map/blob/2baa9fc69e7d69b51239a86180d694df5b202a16/mix.exs#L100-L108 you see that those modules will perform the business use cases.

I don’t need to open many files to implement or work on use cases. Especially that becomes more problematic as the use cases start sharing pieces of code.

With your solution, the issue starts with the fact that all your modules will have a process function or some function that it will implement the use case because your module name is the name of the use case.

In my case, the functions are the name of the use case, and I don’t need to create that many files.

Example: https://github.com/straw-hat-team/straw_hat_map/blob/master/lib/straw_hat_map/world/countries/countries.ex

All the public functions (or at least that will appear on ex_doc documentation are most likely use cases).

The ugly comes when you need multiple use cases in one use cases.

Since you went for the route of using the module name as the use case namespacing, now you will need to import modules when you need to have access to the use case.

Even when you are in the same context, and if you decide to create some function that could is shared between use cases, the mess start becoming even more prominent.

In the approach I ended up with, the use cases for specific context are closer to each other, and it is easier to reuse.

Reduce the entropy between your shared functions.

Module Names vs Folder Structure

Worth to mention that the name of my modules does not follow the folder structure.

The source code is optimized for readability and usability than actually finding files by module names.

You can always do a generic search for function module names, at least you don’t have long names on your modules just because you want to follow the folder structure.

Also module name driven by folder structure makes is harder to move files around since you will have to rename everything.

I tend to create a folder for creating some context and encapsulate files that would most likely live together.

TD; TR

Reduce the entropy of your files and code, the higher the entropy the harder becomes to maintain in, the long term (I love to open Erlang source code because of this)

Use your module as the namespace for your context and use functions as your use cases.

Do not use folder structure as your module name.

Separate files and module based on contexts, no responsibilities.

Clean code is not about conventions.

Conclusion

I hope you find my comment useful.

As I said, I did all the things you propose here and to be honest, I hated myself doing it.

Because of my background from Rails and the habit of convention I had to expirience the pain of learning about this.

I am pleased with the Straw Hat repositories structure, it is nice for consumers of the packages and maintaining it is easier since you don’t need to have that many files open, and the entropy of the files are minimal.

I would say that the only downside is that the folder structure does not represent the module names so you can’t simply assume where the module name locates the file, but you can always search for it, the trade-off.

Still learning and improving, just keep DDD and entropy in mind.

But, no there is nothing wrong with your setup, but subjective speaking I wouldn’t do it since I did exactly what you did and I moved away from it.

joaoevangelista

joaoevangelista

Yes it does! Since most of the time you’ll be sharing schemas across contexts its a good place you put them. Just remove the _ from the folders, so they all can conform on a notation :slight_smile:

yordisprieto

yordisprieto

I need to write another answer here. So much has changed for me that I wouldn’t suggest doing that, except if you don’t have any better strategy. :sweat_smile:

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

We're in Beta

About us Mission Statement