Skip to content

Commit

Permalink
Apply suggestions from code review
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim authored Sep 26, 2023
1 parent babb321 commit 846ff6b
Showing 1 changed file with 10 additions and 15 deletions.
25 changes: 10 additions & 15 deletions lib/elixir/pages/anti-patterns/design-anti-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,36 @@ play within a codebase.

#### Problem

This anti-pattern can be felt when Elixir basic types (for example, *integer*, *float*, and *string*) are abusively used in function parameters and code variables, rather than creating specific composite data types (for example, *structs*, and *map*) that can better represent a domain.
This anti-pattern can be felt when Elixir basic types (for example, *integer*, *float*, and *string*) are abusively used in function parameters and code variables, rather than creating specific composite data types (for example, *tuples* and *structs*) that can better represent a domain.

#### Example

An example of this anti-pattern is the use of a single *string* to represent an `Address`. An `Address` is a more complex structure than a simple basic (aka, primitive) value.

```elixir
defmodule Foo do
@spec bar(String.t()) :: any()
def bar(address) do
defmodule MyApp do
def process_address(address) when is_binary(address) do
# Do something with address...
end
end
```

Another example of this anti-pattern is using floating numbers to model money and currency, when [richer data structures should be preferred](https://hexdocs.pm/ex_money/).

#### Refactoring

We can create an `Address` struct to remove this anti-pattern, better representing this domain through a composite type. Additionally, we can modify the `bar/1` function to accept a parameter of type `Address` instead of a *string*. With this modification, we can extract each field of this composite type individually when needed.
We can create an `Address` struct to remove this anti-pattern, better representing this domain through a composite type. Additionally, we can modify the `process_address/1` function to accept a parameter of type `Address` instead of a *string*. With this modification, we can extract each field of this composite type individually when needed.

Check failure on line 28 in lib/elixir/pages/anti-patterns/design-anti-patterns.md

View workflow job for this annotation

GitHub Actions / Lint Markdown content

Trailing spaces

lib/elixir/pages/anti-patterns/design-anti-patterns.md:28:344 MD009/no-trailing-spaces Trailing spaces [Expected: 0 or 2; Actual: 1] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md009.md

```elixir
defmodule Address do
defstruct street: nil, city: nil, state: nil, postal_code: nil, country: nil

@type t :: %Address{street: String.t(), city: String.t(), state: String.t(), postal_code: integer(), country: String.t()}
defstruct [:street, :city, :state, :postal_code, :country]
end
```

```elixir
defmodule Foo do
@spec bar(Address.t()) :: any()
def bar(address) do
# Some other code...

%Address{postal_code: zip} = address
# Do something with zip...
defmodule MyApp do
def process_address(%Address{} = address) do
# Do something with address...
end
end
```
Expand Down

0 comments on commit 846ff6b

Please sign in to comment.