I've spent two months researching #functionalprogramming and how it applies to #elixirlang. Here are my thoughts on "best practices" for Elixir developers to make your code easy to reason about, debug, test and even run in parallel 🚀
Thread 🧵 (1/10)
(2/10) Don't put *any* logic inside the controllers or GenServers. It will make your code hard to test, difficult to understand and most likely, you will duplicate a lot of it - a bad idea all around.
(3/10) Separate as much of the code into pure functions and leave the "dirty" code(including side effects) in the limited public functions(it's OK to call subfunctions causing side effects). The key here is that "preparation" of data/for side effects can most of the time be pure
(4/10) Making dirty functions testable pt 1 - it's a bad idea to pass side effects causing functions as arguments. You will:
- share implementation details when they shouldn't be
- need to refactor multiple parts when the internal implementation of service changes(like storage).
(5/10) Making dirty functions testable pt 2 - it's a bad idea to pass modules providing side effects causing functions as arguments because of the same reasons that passing functions as arguments. (contexts mixing/global updates requirement in case of internal service' changes)
(6/10) Making dirty functions testable pt 3 - modules used to cause side effects should be set (based on configuration) as modules' attributes. They are easily testable using packages like mox. Controversial: calling `Logger` is a side effect and should be mockd(yes, I wrote it!)
(7/10) Using error handling functional abstractions from Haskell like "Either" and "Maybe" has little sense as Elixir has power `with`in. Seriously, the "with" is like superpowers and should be your new best friend ♥️
(8/10) Chaining lazy computations instead of executing side effects in-place have little sense outside Haskell. It could be useful in very, very specific conditions like RPC, but it was invented to get around the limitation on Haskell, which Elixir does not have - ignore the M.
(9/10) To sum up 7 & 8 point - complex abstractions like Functors have not place outside Haskell and there's no point in introducing them inside Elixir as it has its own ways of dealing with those conditions(or no requirement to!) like pipe operators or the with statement
(10/10) A bit random one that can be controversial - if you are pattern matching inside GenServer multiple times on different parts of the same incoming event to do different actions - you are probably hiding your business logic inside pattern matching, get it out into a pure fn!
• • •
Missing some Tweet in this thread? You can try to
force a refresh
I decided to *keep* my book both open-source and freely available online. IMO this the only way to prolong its value for the community, and I can make continuous maintenance of it sustainable 🚀
Read the thread below to check how I plan to do it 👇
(2/11) In the past couple of days, I had conversations on the topic of monetizing the open-sourced book🤔. In the end, a lot of effort needs to be put into writing the book, and then continuous updating requires dedication and commitment(similar to any other open source project).
(3/11) The theory is that making the book open-source and freely available to read online will cause me to lose all potential sales profits. I believe that nobody should be banned from benefiting from it because of a lack of financial resources, so I can't sell it.