You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -45,75 +46,6 @@ We removed the unnecessary comments. We also added a `@five_min_in_seconds` modu
45
46
46
47
Elixir makes a clear distinction between **documentation** and code comments. The language has built-in first-class support for documentation through `@doc`, `@moduledoc`, and more. See the ["Writing documentation"](../getting-started/writing-documentation.md) guide for more information.
47
48
48
-
## Complex branching
49
-
50
-
#### Problem
51
-
52
-
When a function assumes the responsibility of handling multiple errors alone, it can increase its cyclomatic complexity (metric of control-flow) and become incomprehensible. This situation can configure a specific instance of "Long function", a traditional anti-pattern, but has implications of its own. Under these circumstances, this function could get very confusing, difficult to maintain and test, and therefore bug-proneness.
53
-
54
-
#### Example
55
-
56
-
An example of this anti-pattern is when a function uses the `case` control-flow structure or other similar constructs (for example, `cond` or `receive`) to handle variations of a return type. This practice can make the function more complex, long, and difficult to understand, as shown next.
57
-
58
-
```elixir
59
-
defget_customer(customer_id) do
60
-
caseSomeHTTPClient.get("/customers/#{customer_id}") do
61
-
{:ok, %{status:200, body: body}} ->
62
-
caseJason.decode(body) do
63
-
{:ok, decoded} ->
64
-
%{
65
-
"first_name"=> first_name,
66
-
"last_name"=> last_name,
67
-
"company"=> company
68
-
} = decoded
69
-
70
-
customer =
71
-
%Customer{
72
-
id: customer_id,
73
-
name:"#{first_name}#{last_name}",
74
-
company: company
75
-
}
76
-
77
-
{:ok, customer}
78
-
79
-
{:error, _} ->
80
-
{:error, "invalid response body"}
81
-
end
82
-
83
-
{:error, %{status: status, body: body}} ->
84
-
caseJason.decode(body) do
85
-
%{"error"=> message} whenis_binary(message) ->
86
-
{:error, message}
87
-
88
-
%{} ->
89
-
{:error, "invalid response with status #{status}"}
90
-
end
91
-
end
92
-
end
93
-
```
94
-
95
-
The code above is complex because the `case` clauses are long and often have their own branching logic in them. With the clauses spread out, it is hard to understand what each clause does individually and it is hard to see all of the different scenarios your code pattern matches on.
96
-
97
-
#### Refactoring
98
-
99
-
As shown below, in this situation, instead of concentrating all error handling within the same function, creating complex branches, it is better to delegate each branch to a different private function. In this way, the code will be cleaner and more readable.
100
-
101
-
```elixir
102
-
defget_customer(customer_id) do
103
-
caseSomeHTTPClient.get("/customers/#{customer_id}") do
104
-
{:ok, %{status:200, body: body}} ->
105
-
http_customer_to_struct(customer_id, body)
106
-
107
-
{:error, %{status: status, body: body}} ->
108
-
http_error(status, body)
109
-
end
110
-
end
111
-
```
112
-
113
-
Both `http_customer_to_struct(customer_id, body)` and `http_error(status, body)` above contain the previous branches refactored into private functions.
114
-
115
-
It is worth noting that this refactoring is trivial to perform in Elixir because clauses cannot define variables or otherwise affect their parent scope. Therefore, extracting any clause or branch to a private function is a matter of gathering all variables used in that branch and passing them as arguments to the new function.
Copy file name to clipboardExpand all lines: lib/elixir/pages/anti-patterns/what-anti-patterns.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -38,4 +38,4 @@ Each anti-pattern is documented using the following structure:
38
38
39
39
The initial catalog of anti-patterns was proposed by Lucas Vegi and Marco Tulio Valente, from [ASERG/DCC/UFMG](http://aserg.labsoft.dcc.ufmg.br/). For more info, see [Understanding Code Smells in Elixir Functional Language](https://github.com/lucasvegi/Elixir-Code-Smells/blob/main/etc/2023-emse-code-smells-elixir.pdf) and [the associated code repository](https://github.com/lucasvegi/Elixir-Code-Smells).
40
40
41
-
Additionally, the Security Working Group of the [Erlang Ecosystem Foundation](https://erlef.github.io/security-wg/) publishes [documents with security resources and best-practices of both Erland and Elixir, including detailed guides for web applications](https://erlef.github.io/security-wg/).
41
+
Additionally, the Security Working Group of the [Erlang Ecosystem Foundation](https://erlef.github.io/security-wg/) publishes [documents with security resources and best-practices of both Erlang and Elixir, including detailed guides for web applications](https://erlef.github.io/security-wg/).
Copy file name to clipboardExpand all lines: lib/elixir/pages/getting-started/alias-require-and-import.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -112,7 +112,7 @@ end
112
112
113
113
In the example above, the imported `List.duplicate/2` is only visible within that specific function. `duplicate/2` won't be available in any other function in that module (or any other module for that matter).
114
114
115
-
Note that `import`s are generally discouraged in the language. When working on your own code, prefer `alias` to `import`.
115
+
While `import`s can be a useful for frameworks and libraries to build abstractions, developers should generally prefer `alias` to `import` on their own codebases, as aliases make the origin of the function being invoked clearer.
0 commit comments