By far the most loved library on the Panel today was Telemetry. Telemetry powers monitoring and observability in elixir projects and provides a consistent interface to do so. Other mentions were OTP, Livebook, and site_encrypt.
1/24
When members of today's panel came into the Elixir Industry, they found opinions they like and trust from the Elixir community but also questioned established norms. Thus today's topic: Code Heresy.
2/24
So let's throw out our perceived notions from other runtimes and languages to consider alternatives.
These are strong opinions that may cause controversial feedback.
3/24
But first, let's understand design.
What is the purpose of design? To create an extensible system to build quickly in a complex domain and allow for future growth.
4/24
A bad design can be: over-designed, under-designed, and designed in the wrong direction.
5/24
Future growth does not mean "future-proofing." Future-proofing is an example of over-design or designing in the wrong direction. You attempt to read the future of your application and guess incorrectly, leading to unnecessary complexity.
6/24
Accommodating future growth does mean getting the design right for what you know. It means taking into account how much you need to design given the potential longevity of the project.
7/24
Signs of overdesign include going for scale to start, designing too early before you have enough information to know which abstractions are correct, and caching before it's necessary.
8/24
Adding caching to your application is particularly dangerous because you couple yourself to time. Coupling yourself to time is one of the worst things you can do, as it makes your system nearly impossible to reason about.
9/24
The best philosophy to design is that if you don't need it, don't do it. If a function does, then use a simple function. However, it's time to design and abstract ideas when the cost of change becomes high.
10/24
If you have to wade through multiple system layers for any specific change, that's a sign of overdesign. Instead, a well-designed system should hide the complexity of the lower layers so that you never need to worry about them.
11/24
Complexity is a multiplication of the actual domain complexity * the number of times you need to care about it. Thus, reducing the number of times you need to care about it to 0 eliminates complexity.
12/24
The network stack is a perfect example of hiding complexity. When was the last time you needed to care about TCP or packets?
13/24
Now that we have a better understanding of the goal of design, it makes sense why @ChrisKeathley doesn't like the current context pattern established by phoenix.
For..context (sorry). Chris defines a context as the pattern of generating files done by phoenix.
14/24
Core Criticisms included: Contexts do not hide layers below them, Contexts do not hide any complexity inside them. Contexts expose ecto to you. In Contexts, any specific change often requires editing the controller, view, schema, and multiple system layers.
15/24
This may even be a fundamental problem with the Model View Controller pattern. Controllers are by design not reusable, and the layers in the system are not generic enough to allow you to ignore them. Likewise, contexts are also not reusable.
16/24
Instead, consider moving your layers up and putting more control in the call site. Chris discovered this pattern when dealing with large traffic applications, and one of the easy ways to hide poor performance choices is by hiding calls to the db.
17/24
Graphql attempts to do this by giving the client the ability to control what data it retrieves. However, it brings other problems with it.
In the same pattern of thought, you may consider moving control to the LiveView.
18/24
To accomplish polymorphism in Elixir, you have several methods: data and functions, behaviors, and protocols. In many cases: the best dependency injection is passing arguments to functions.
19/24
This allows you to take apart the truly reusable abstraction and the specific usage.
For example, you may have a function that takes in a function or even a module. Then calls that function or module with specific arguments.
20/24
Also talked about was the Norm library. This library allows you to create contracts of input and output using a rich data language.
Chris loves conversations about how to improve how we write software, but not just how we improve a little bit. How do we improve by an order of magnitude difference? He's always on the lookout for the next idea that helps achieve that goal.
22/24
Because of this, Chris is no stranger to strong opinions that cause controversial feedback.
I think it's important to remember Chris is trying to make the software industry better, even if you disagree.
23/24
As usual, I just summarize the information. I do not represent anyone at @BeamRadio1 nor do I agree with (or understand) everything discussed 😅
But I do learn a ton and have a lot of fun sharing.
Raspberry pi is a great way to get your start in IoT, and Nerves and Livebook take that even further. Cool enough: the first real Elixir code Lars wrote was for the Rasberry Pi Zero.
1/13
You can sandwich a Rasberry Pi and an eInk display together. The Rasberry Pi runs your application and your application can use The Libraries Inky and Chisel to write to the display.
Bottom line, before the end of September, if you are on Elixir OTP 23 or 24 you should upgrade to the latest patch.
specifically OTP 23.3.4.5 or OTP 24.0.4
If you are on an OTP version older than 23, the good news is you will be unaffected so long as you do not upgrade your dependencies. You can freeze your dependencies in order to buy yourself time to upgrade to OTP 23 or 24.
Error handling can be tricky, and can cause a task you would expect to take a single day to instead take a whole week!
1/10
This episode is focused on dealing with errors caused by working with external services. Anytime you're dealing with external dependency, you expose yourself to risk.