Using Elixir modules to organize logic when you don’t have classes

Joel Kemp
Elixir Learnings
Published in
2 min readSep 17, 2020

I had this realization of Elixir module organization as I was working through a multiplayer TicTacToe game using LiveView: an Elixir (struct) module is a struct definition with colocated methods that act on instances of that struct.

If you’re writing code that acts on a struct, ask yourself if you’re reaching too much into the internals of that struct or if you’d be better suited putting that logic in a method in the struct’s module.

For example, in my game, I had a Game module and a Board module, each of which defines their own structs. In my Game module, it has an instance of a %Board{}.

A game is complete if the board has a winning move or it’s a tie. You could define all of the logic that examines the board and looks at columns, rows, and diagonals and deduces the win/draw state. That would keep your Board module pretty thin and really only a struct definition; but you end up with your Game module getting pretty bloated.

An alternative, which led to my understanding of how to leverage modules for code organization, is to move that logic that checks for a win/draw state into the Board module. The Game module would then call Board.has_winner?(board) or Board.is_draw?(board) like this:

This conceptually reminds me of structs in the C language: a struct being just a collection of attributes and there are some neighboring functions that act on instances of that struct (i.e., snapshots of state). This is in contrast to a traditional class: where the class has data attributes and the co-located functions have direct access to manipulating those attributes.

Without the notion of a class in Elixir, I felt really unsure where to put logic: do I spawn processes to encapsulate state, do I keep a struct in isolation with a neighboring client module (almost like separate header and implementation files in C++), or do I just keep everything in a single module (but how do I deal with it bloating and separate concerns)?

I’m glad I was able to really come to appreciate the module structure as a tool for maximizing cohesion and organizing my application logic.

--

--