AstonJ

AstonJ

Single Responsibility Principle - what does it mean to you and your Elixir apps?

There is a wikipedia definition on this but it doesn’t really cover how you can go further in functional programming. I feel PragDave’s comment (from his course) is better from an Elixir perspective:

I know I’m like a broken record, but I can’t help it. I’m really excited to see how a functional approach makes it so much easier to honor the SRP, both at the function and module level. The fact that state is passed around, and not simply shared, means that functions can and modules can both be split and moved around.

What does the SRP mean to you? How far do you go? How strictly to you adhere to these (or your own) guidelines?

Most Liked

hubertlepicki

hubertlepicki

I have a theory that a lot of these things we learned when doing OOP, no longer make sense when you switch to functional programming. This is precisely because they solve problems that are a result of using Object-Oriented programming in first place.

Take this single responsibility principle for a review, and compare this to how things from standard library work. In either version (one responsibility, one reason to change), this is being broken all the time.

In Elixir & Erlang, modules group together the related functions. That’s it, there’s no big theory behind it. These functions may perform one or multiple things, but as long as it makes sense to keep them in the same module - they are kept there.

sasajuric

sasajuric

Author of Elixir In Action

I personally believe that on some higher-level of thinking many ideas transcend paradigms. In particular, I think that a large module which deals with many things is more problematic to read and understand.

A typical example I see is a case where complex GenServer state is handled directly in the GenServer module. By moving the state manipulation to a separate module, we can separate the domain logic from the time-flow logic, and this allows us to study each aspect of our system in isolation.

For a more concrete example, see my example blackjack code from my To spawn, or not to spawn? article. The domain management is done in separate modules, which means that domain code is not polluted with GenServer and vice versa.

IMO the case for short classes (and also modules and functions) is to allow the reader to understand a single concept without worrying about non-essential details. Being able to understand a domain model without caring how it’s used from the rest of the system simplifies the code analysis, debugging, and extension.

I should also mention that I’m not a purist here. For example, if the process state is simple enough, I just bundle it inside the GenServer. If the model grows, then I split.

But tl;dr I believe that SRP and similar ideas, vague as they are, still apply in FP.

hubertlepicki

hubertlepicki

I think @pragdave might be importing some wisdom from his object-oriented life ;). I was thinking about it when I first opened Elixir’s own source code files, or sources of prominent Elixir libraries like Ecto, and was shocked by the large files containing hundreds of lines of code (+many more lines of documentation). In Erlang they even add a lot of unit tests at the end of the file to keep the tests close to the module they test! (moduledoc in Elixir but more popular I think)

But then, I realized what is a reason for having a short classes and it suddenly made more sense. The reason why we want to keep our classes short and clean is that we can mentally model how instances of this class will behave, and how they will modify the object’s attributes in it’s life cycle. So - we couple state to the functions that operate on this state, and we want this to be as small as possible - otherwise we easily loose track of how this works, and bugs sneak in.

In Elixir, the module has no state. The main reason for keeping classes short does not apply here anymore. Of course, it becomes tiresome to work with files that are thousands lines long, but there is no such thing as internal state of object to be concerned with.

Having said the above: again, the object-oriented wisdom of keeping classes short does have it’s place in Elixir, and again this is when you create processes (GenServer etc). I think it makes total sense to keep them short in terms of lines of code and focused on one thing.

Where Next?

Popular in Discussions Top

PragTob
Hello everyone, I know we had quite some threads (read through lots of them) about background job processing but it remains a hotly deba...
New
ben-pr-p
In general I’ve been sticking to this community style guide GitHub - christopheradams/elixir_style_guide: A community driven style guide ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39523 209
New
AlexMcConnell
The reason that Rails is as popular as it is is because it’s very easy for relatively inexperienced developers to get a lot of work done....
588 19675 166
New
chulkilee
Here are the list of HTTP client libraries/wrappers, and some thoughts on HTTP client in general. I’d like to hear from others how they w...
New
tomekowal
Hey guys! I want to create a toy project that shows a chart of temperature over time and updates every 5 seconds. I feel LiveView is per...
New
fireproofsocks
This is more of a general question, but I’m wondering how other people in the community think about the pattern matching in function sign...
New
sashaafm
Piggy backing a bit on @dvcrn topic BEAM optimization for functions with static return type?, I’ve been trying to understand in a deeper ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
AstonJ
It’s been a while since we’ve had a thread like this, so what better way to kick off the year with :003: What does being an Elixir user ...
New

Other popular topics Top

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
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42158 114
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
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 Postgres...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New

We're in Beta

About us Mission Statement