Elixir Anti-Patterns
The document discusses code-related anti-patterns in Elixir v1.18.0-dev, highlighting issues like comments overuse, complex 'with' expressions, dynamic atom creation, long parameter lists, and namespace conventions. It provides examples and refactoring suggestions to improve code quality and maintainability.
Read original articleThe document discusses code-related anti-patterns in Elixir v1.18.0-dev. It highlights issues like comments overuse, complex else clauses in 'with' expressions, complex extractions in clauses, dynamic atom creation, long parameter lists, and namespace trespassing. Examples and refactoring suggestions are provided for each anti-pattern to improve code readability and maintainability. For instance, it advises against creating atoms dynamically due to potential memory issues and suggests using explicit conversions or existing atoms. Similarly, it recommends grouping related arguments using key-value data structures to address the problem of long parameter lists. The document emphasizes the importance of adhering to namespace conventions to prevent module name clashes in libraries. Overall, it provides insights into common pitfalls in Elixir coding practices and offers solutions to enhance code quality.
Related
Orb: Write WebAssembly with Elixir
Orb leverages Elixir's ecosystem to simplify WebAssembly writing, offering features like composable modules, Hex package manager, ExUnit testing, macros, and syntax highlighting. It enables Elixir code compilation to .wasm, supports reusable modules, and integrates existing Elixir libraries for MIME tasks, showcasing flexibility in WebAssembly development.
Avoiding Emacs Bankruptcy
Avoid "Emacs bankruptcy" by choosing efficient packages, deleting unnecessary configurations, and focusing on Emacs's core benefits. Prioritize power-to-weight ratio to prevent slowdowns and maintenance issues. Regularly reassess for a streamlined setup.
Elixir Gotchas
The article highlights common pitfalls in Elixir programming, including confusion between charlists and strings, differences in pattern matching, struct behavior, accessing struct fields, handling keyword lists, and unique data type comparisons.
Elixir for Python Developers
This comparison delves into Python and Elixir, emphasizing syntax disparities and distinctive traits. Elixir prioritizes immutability and pattern matching, while Python focuses on object-oriented elements. Both share list comprehensions and parallel processing, yet Elixir's functional approach and pattern matching distinguish it. Elixir's Stream module supports lazy operations for big data, contrasting Python's I/O streams. Python developers can benefit from exploring Elixir.
Elixir for Humans Who Know Python
The article explores transitioning from Python to Elixir, emphasizing Elixir's concurrency, Phoenix framework, LiveView feature, immutability, and pattern matching. It compares Elixir's functionalism and control flow to Python, showcasing Elixir's efficiency for web development.
This has proven controversial, but sometimes the Else behavior is very sensitive to which of the With expressions failed (especially for better logging) and I maintain that the least terrible approach involves augmenting the With clauses using atoms to identify each expression when it fails, ex:
For example:
with {_, {:ok, key} } <- {:phase_key, get_key() },
{_, {:ok, door}} <- {:phase_unlock, unlock(door) },
{_, %Thingy{} } <- {:phase_thingy, fetch_thingy(door)},
{_, %Widget{} } <- {:phase_widget, fetch_widget(door)} do
else
{:phase_key, {:error, _msg} = err} -> # I can tell the key was missing, rather than the lock broke
{:phase_unlock, {:error, _msg} = err} -> # I can tell the lock broke, rather than missing a key
{:phase_thingy, nil } -> # I can tell this nil value is a missing thingy, not a widget
{:phase_widget, nil } -> # I can tell this nil value is a missing widget, not a thingy
end
As a big bonus, when something crazy-unexpected is emitted to cause a WithClauseError--like "hello world"--you have a much better chance of quickly diagnosing what happened from log messages, instead of inspecting a dozen different logical branching or trying to blindly repro it.Pre-buttals:
"Just rewrite those 4 functions to return better somehow" -> No, that's not always practical or even possible. In the above example, the signatures of some of these functions are already perfectly fine on their own. The ambiguity comes when they get used near others in different ways, and trying to assign globally unique features to match on is a bad idea.
"Create 4 private functions to wrap things" -> Ugh, now the person reading the code has an even harder time, since they need to refer to functions elsewhere in the file, any of which might be hiding unexpected bonus behavior. Those 4 private functions might not even be useful in other with-statements in the same module, causing you to make even more private functions... and all of it still falls apart the moment your Else logging/cleanup needs to record or revert something from a prior (successful) step.
For non-Elixir folks, imagine something that looks like a regular function-call where expressions are evaluated and the results are passed in... but in reality all arguments are symbolic inputs to something that emits new code.
For example, you might see this unassuming line in your editor:
describe_combo(a(foo),b(bar))
But what might actually be compiled is: # What might actually get compiled
# Runtime results like "a(1)+b(2)=3"
"a(" <> to_string(foo) <> ")+b(" <> to_string(bar) <> ")=" to_string(a(foo)+b(bar))
And if someone in your codebase is an evil misanthrope: foo = "haha I changed your local variable"
IO.puts("surprise, suckers") # Prints to console
kick_puppies()
Macros are actually part of the core DNA of the language and underpin how some of its syntax works... but with great power comes great potential for WTF.Instead, I'm stuck writing applications in Go which is a language I absolutely despise but can't deny it's ability to get shit done regardless of the insane amount of boilerplate code I have to write.
Any predictions on whether Elixir will eventually gain more traction? The language and platform are rock solid and it's the best developer experience I've encountered. Phoenix is by far my favorite web framework and just feels very intuitive and complete. The lack of a good IDE is one huge pain point that I can't seem to overcome (I don't care how much people praise it, I know it's the best but VSCode is awful for Elixir development).
I just wish this language was more popular because it deserves to be!
Related
Orb: Write WebAssembly with Elixir
Orb leverages Elixir's ecosystem to simplify WebAssembly writing, offering features like composable modules, Hex package manager, ExUnit testing, macros, and syntax highlighting. It enables Elixir code compilation to .wasm, supports reusable modules, and integrates existing Elixir libraries for MIME tasks, showcasing flexibility in WebAssembly development.
Avoiding Emacs Bankruptcy
Avoid "Emacs bankruptcy" by choosing efficient packages, deleting unnecessary configurations, and focusing on Emacs's core benefits. Prioritize power-to-weight ratio to prevent slowdowns and maintenance issues. Regularly reassess for a streamlined setup.
Elixir Gotchas
The article highlights common pitfalls in Elixir programming, including confusion between charlists and strings, differences in pattern matching, struct behavior, accessing struct fields, handling keyword lists, and unique data type comparisons.
Elixir for Python Developers
This comparison delves into Python and Elixir, emphasizing syntax disparities and distinctive traits. Elixir prioritizes immutability and pattern matching, while Python focuses on object-oriented elements. Both share list comprehensions and parallel processing, yet Elixir's functional approach and pattern matching distinguish it. Elixir's Stream module supports lazy operations for big data, contrasting Python's I/O streams. Python developers can benefit from exploring Elixir.
Elixir for Humans Who Know Python
The article explores transitioning from Python to Elixir, emphasizing Elixir's concurrency, Phoenix framework, LiveView feature, immutability, and pattern matching. It compares Elixir's functionalism and control flow to Python, showcasing Elixir's efficiency for web development.