An open API service indexing awesome lists of open source software.

https://github.com/lucasvegi/elixir-refactorings

Catalog of Elixir Refactorings
https://github.com/lucasvegi/elixir-refactorings

elixir elixir-examples elixir-lang refactoring software-quality

Last synced: about 1 year ago
JSON representation

Catalog of Elixir Refactorings

Awesome Lists containing this project

README

          

# [Catalog of Elixir Refactorings][Elixir Refactorings]

[![GitHub last commit](https://img.shields.io/github/last-commit/lucasvegi/Elixir-Refactorings)](https://github.com/lucasvegi/Elixir-Refactorings/commits/main)
[![Twitter URL](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2Flucasvegi%2FElixir-Refactorings)](https://twitter.com/intent/tweet?url=https%3A%2F%2Fgithub.com%2Flucasvegi%2FElixir-Refactorings&via=lucasvegi&text=Catalog%20of%20Elixir%20Refactorings%3A&hashtags=MyElixirStatus%2CElixirLang)

## Table of Contents

* __[Introduction](#introduction)__
* __[Elixir-Specific Refactorings](#elixir-specific-refactorings)__
* [Alias expansion](#alias-expansion) [^**]
* [Default value for an absent key in a Map](#default-value-for-an-absent-key-in-a-map) [^**]
* [Defining a subset of a Map](#defining-a-subset-of-a-map) [^**]
* [Modifying keys in a Map](#modifying-keys-in-a-map) [^**]
* [Simplifying Ecto schema fields validation](#simplifying-ecto-schema-fields-validation) [^**]
* [Pipeline using "with"](#pipeline-using-with) [^**]
* [Pipeline for database transactions](#pipeline-for-database-transactions) [^**]
* [Transform nested "if" statements into a "cond"](#transform-nested-if-statements-into-a-cond) [^**]
* [Explicit a double boolean negation](#explicit-a-double-boolean-negation) [^**]
* [Transform "if" statements using pattern matching into a "case"](#transform-if-statements-using-pattern-matching-into-a-case) [^**]
* [Moving "with" clauses without pattern matching](#moving-with-clauses-without-pattern-matching) [^**]
* [Remove redundant last clause in "with"](#remove-redundant-last-clause-in-with) [^***]
* [Replace "Enum" collections with "Stream"](#replace-enum-collections-with-stream) [^***]
* [Generalise a process abstraction](#generalise-a-process-abstraction) [^***]
* __[Traditional Refactorings](#traditional-refactorings)__
* [Rename an identifier](#rename-an-identifier)
* [Moving a definition](#moving-a-definition)
* [Add or remove a parameter](#add-or-remove-a-parameter)
* [Grouping parameters in tuple](#grouping-parameters-in-tuple)
* [Reorder parameter](#reorder-parameter)
* [Extract function](#extract-function)
* [Inline function](#inline-function)
* [Folding against a function definition](#folding-against-a-function-definition)
* [Extract constant](#extract-constant)
* [Temporary variable elimination](#temporary-variable-elimination)
* [Extract expressions](#extract-expressions)
* [Splitting a large module](#splitting-a-large-module)
* [Remove nested conditional statements in function calls](#remove-nested-conditional-statements-in-function-calls)
* [Move file](#move-file)
* [Remove dead code](#remove-dead-code)
* [Introduce a temporary duplicate definition](#introduce-a-temporary-duplicate-definition)
* [Introduce overloading](#introduce-overloading)
* [Remove import attributes](#remove-import-attributes)
* [Introduce import](#introduce-import)
* [Group Case Branches](#group-case-branches)
* [Move expression out of case](#move-expression-out-of-case)
* [Simplifying checks by using truthness condition](#simplifying-checks-by-using-truthness-condition) [^**]
* [Reducing a boolean equality expression](#reducing-a-boolean-equality-expression) [^**]
* [Transform "unless" with negated conditions into "if"](#transform-unless-with-negated-conditions-into-if) [^**]
* [Replace conditional with polymorphism via Protocols](#replace-conditional-with-polymorphism-via-protocols) [^**]
* __[Functional Refactorings](#functional-refactorings)__
* [Generalise a function definition](#generalise-a-function-definition)
* [Introduce pattern matching over a parameter](#introduce-pattern-matching-over-a-parameter)
* [Turning anonymous into local functions](#turning-anonymous-into-local-functions)
* [Merging multiple definitions](#merging-multiple-definitions)
* [Splitting a definition](#splitting-a-definition)
* [Inline macro](#inline-macro)
* [Transforming list appends and subtracts](#transforming-list-appends-and-subtracts)
* [From tuple to struct](#from-tuple-to-struct)
* [Struct guard to matching](#struct-guard-to-matching)
* [Struct field access elimination](#struct-field-access-elimination)
* [Equality guard to pattern matching](#equality-guard-to-pattern-matching)
* [Static structure reuse](#static-structure-reuse)
* [Simplifying guard sequences](#simplifying-guard-sequences)
* [Converts guards to conditionals](#converts-guards-to-conditionals)
* [Widen or narrow definition scope](#widen-or-narrow-definition-scope)
* [Introduce Enum.map/2](#introduce-enummap2)
* [Merging match expressions into a list pattern](#merging-match-expressions-into-a-list-pattern)
* [Function clauses to/from case clauses](#function-clauses-tofrom-case-clauses)
* [Transform a body-recursive function to a tail-recursive](#transform-a-body-recursive-function-to-a-tail-recursive)
* [Eliminate single branch](#eliminate-single-branch)
* [Transform to list comprehension](#transform-to-list-comprehension)
* [Nested list functions to comprehension](#nested-list-functions-to-comprehension)
* [List comprehension simplifications](#list-comprehension-simplifications)
* [Closure conversion](#closure-conversion) [^*]
* [Replace pipeline with a function](#replace-pipeline-with-a-function) [^**]
* [Remove single pipe](#remove-single-pipe) [^**]
* [Simplifying pattern matching with nested structs](#simplifying-pattern-matching-with-nested-structs) [^**]
* [Improving list appending performance](#improving-list-appending-performance) [^**]
* [Convert nested conditionals to pipeline](#convert-nested-conditionals-to-pipeline) [^**]
* [Replacing recursion with a higher-level construct](#replacing-recursion-with-a-higher-level-construct) [^**]
* [Replace a nested conditional in a "case" statement with guards](#replace-a-nested-conditional-in-a-case-statement-with-guards) [^***]
* [Replace function call with raw value in a pipeline start](#replace-function-call-with-raw-value-in-a-pipeline-start) [^***]
* __[Erlang-Specific Refactorings](#erlang-specific-refactorings)__
* [Typing parameters and return values](#typing-parameters-and-return-values)
* [Moving error-handling mechanisms to supervision trees](#moving-error-handling-mechanisms-to-supervision-trees)
* [From meta to normal function application](#from-meta-to-normal-function-application)
* [Remove unnecessary calls to length/1](#remove-unnecessary-calls-to-length1)
* [Add type declarations and contracts](#add-type-declarations-and-contracts)
* [Introduce processes](#introduce-processes)
* [Remove processes](#remove-processes)
* [Add a tag to messages](#add-a-tag-to-messages)
* [Register a process](#register-a-process)
* [Behaviour extraction](#behaviour-extraction)
* [Behaviour inlining](#behaviour-inlining)
* __[About](#about)__
* __[Acknowledgments](#acknowledgments)__

[^*]: This refactoring emerged from an extended Systematic Literature Review (SLR).
[^**]: This refactoring emerged from a Grey Literature Review (GLR).
[^***]: This refactoring emerged from a Mining Software Repositories (MSR) study.

## Introduction

[Elixir][Elixir] is a functional programming language whose popularity is on the rise in the industry [link][ElixirInProduction]. As no known studies have explored refactoring strategies for code implemented with this language, we reviewed scientific literature seeking refactoring strategies in other functional languages. The found refactorings were analyzed, filtering only those directly compatible or that could be adapted for Elixir code. As a result of this investigation, we have initially proposed a catalog of 55 refactorings for Elixir systems.

Afterward, we scoured websites, blogs, forums, and videos (grey literature review), looking for specific refactorings for Elixir that its developers discuss. With this investigation, the catalog was expanded to 76 refactorings. Finally, 6 new refactorings emerged from a study mining software repositories (MSR) performed by us, so this catalog is constantly being updated and *__currently has 82 refactorings__*. These refactorings are categorized into four different groups ([Elixir-specific](#elixir-specific-refactorings), [traditional](#traditional-refactorings), [functional](#functional-refactorings), and [Erlang-specific](#erlang-specific-refactorings)), according to the programming features required in code transformations. This catalog of Elixir refactorings is presented below. Each refactoring is documented using the following structure:

* __Name:__ Unique identifier of the refactoring. This name is important to facilitate communication between developers;
* __Category:__ Scope of refactoring in relation to its application coverage;
* __Motivation:__ Description of the reason why this refactoring should be done and what this refactoring does to the code;
* __Examples:__ Illustrates the resulting code from the refactoring, showing versions of it before and after the transformation;
* __Side-conditions (*):__ Minimum requirements to perform refactoring without creating conflicts with other parts of the code that may depend on the transformations promoted;
* __Mechanics (*):__ Sequence of main steps for the promoted code transformations.

__Note:__ (*) not all refactorings have explicit definitions for these fields.

__Tool support:__ [RefactorEx](https://github.com/gp-pereira/refactorex) is a VS Code extension inspired by this catalog that can semi-automatically apply some of the refactoring strategies defined here. Please take a look!

This catalog of refactorings aims to improve the quality of code developed in Elixir, helping developers promote the redesign of their code, making it simpler to understand, modify, or even improving performance. These transformations must be performed without changing the original behavior, thus preserving the code's functionality. For this reason, we are interested in knowing Elixir's community opinion about these refactorings: *Do you agree that these refactorings can be useful? Have you seen any of them in production code? Do you have any suggestions about some Elixir-specific refactorings not cataloged by us?...*

Please feel free to make pull requests and suggestions ([Issues][Issues] tab). We want to hear from you!

[▲ back to Index](#table-of-contents)

## Elixir-Specific Refactorings

Elixir-specific refactorings are those that use programming features unique to this language. In this section, 14 different refactorings classified as Elixir-specific are explained and exemplified:

### Alias expansion

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ In Elixir, when using an `alias` for multiple names from the same namespace, you can sort and consolidate them within a single file, reducing redundancy. Although this programming practice is common and can reduce the number of lines of code, multi-aliases can make it harder to search for a dependency in large code bases. This refactoring aims to expand multi-alias instructions fused into one multi-instruction per namespace, transforming them into single alias instructions per name. This provides improvement in code readability and traceability.

* __Examples:__ In the following code, before refactoring, we have a multi-alias instruction combining the definition of two dependencies. In this particular case, the dependencies for the `Baz` and `Boom` modules were merged into a single instruction.

```elixir
# Before refactoring:

alias Foo.Bar.{Baz, Boom}
```

Especially in larger code bases, involving a greater number of dependencies within the same namespace (nested modules), the definition of these aliases could be refactored by an *__alias expansion__*, better highlighting all dependencies, as shown in the following code.

```elixir
# After refactoring:

alias Foo.Bar.Baz
alias Foo.Bar.Boom
```

This example is derived from code found in the official documentation for the tools [Recode](https://hexdocs.pm/recode/0.6.5/Recode.Task.AliasExpansion.html) and [ExactoKnife](https://hexdocs.pm/exacto_knife/readme.html#refactorings).

* __Side-conditions:__
* The number of `alias` commands inserted by this refactoring is identical to the number of modules that were originally merged into a single `alias` instruction (*i.e.*, inside a `{}`, such as `{Baz, Boom}`);

* Each of the `alias` instructions inserted by this refactoring should start with the path that was shared by the modules originally merged (*e.g.*, `Foo.Bar`), followed by a `.` and the name of one of the modules that were previously imported by a single command (*e.g.*, `Bar` or `Boom`).

[▲ back to Index](#table-of-contents)
___

### Default value for an absent key in a Map

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ We often come across a situation where we expect a `Map` to have a certain key, and if not, we need to provide a default value. A commonly used alternative for such situations is using the built-in `Map.has_key?/2` function along with an `if...else` statement. Although this alternative works perfectly, it's possible to refactor this code using only the built-in `Map.get/3` function, making the code less verbose and more readable, while preserving the same behavior.

* __Examples:__ In the following code, before refactoring, we utilize the `Map.has_key?/2` function in conjunction with an `if...else` statement to retrieve the currency from a ``Map`` containing the price of a product. If the `currency` key does not exist, we return the default value of `"USD"`.

```elixir
# Before refactoring:

currency =
if(Map.has_key?(price, "currency")) do
price["currency"]
else
"USD"
```

Applying this refactoring, the above code can be transformed into the following code, preserving the behavior while reducing the number of lines.

```elixir
# After refactoring:

currency = Map.get(price, "currency", "USD")
```

This example is based on an original code by Malreddy Ankanna. Source: [link](https://medium.com/blackode/elixir-code-refactoring-techniques-33589ac56231)

* __Side-conditions:__
* To be eligible for this refactoring, the code snippet must consist of an `if..else` statement, where the condition checked is a call to the built-in function `Map.has_key?/2`. Additionally, the branch created by the `if` should only return the value of the key in the ``Map`` whose existence was checked by the call to `Map.has_key?/2`, while the branch defined by the `else` should only return a default value for a non-existent key.

[▲ back to Index](#table-of-contents)
___

### Defining a subset of a Map

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ When dealing with huge `Map` structures, there are occasions when we need to extract a subset of elements to form a new `Map`. Instead of manually creating this subset by individually accessing each of the desired key/value pairs from the original `Map`, with this refactoring, we can simply use the built-in `Map.take/2` function.

* __Examples:__ In the following code, we have a variable `pickup` bound to a `Map` composed of a huge number of keys.

```elixir
# Huge Map
pickup = %{
"zip" => "75010",
"town" => "PARIS",
"stopName" => "RECEPTION",
"pickupId" => 4018,
"longitude" => 2.360982,
"latitude" => 48.868502
.... #a lot of keys
}
```

To extract only the metadata related to location, before refactoring, we manually access the values identified by the keys `"latitude"` and `"longitude"` to then create a new `Map`.

```elixir
# Before refactoring:

longitude = pickup["longitude"]
latitude = pickup["latitude"]

location = %{ # <-- Defining a subset manually
"longitude" => longitude,
"latitude" => latitude
}
```

Although this solution works, it can generate a significant amount of code, primarily due to duplications. Applying this refactoring, we can eliminate duplicated code, significantly reducing the number of lines and improving readability.

```elixir
# After refactoring:

location = Map.take(pickup, ["latitude", "longitude"])
```

This example is based on an original code by Malreddy Ankanna. Source: [link](https://medium.com/blackode/elixir-code-refactoring-techniques-33589ac56231)

* __Side-conditions:__
* To be eligible for this refactoring, the code snippet must originally create a subset of a ``Map`` manually, meaning it constructs a new ``Map`` containing only some of the key/value pairs from the complete ``Map``;

* The number of elements in the list passed as the second parameter of the `Map.take/2` call in the refactored version of the code must be identical to the number of key/value pairs that originally composed the manually created subset. Additionally, the elements of this list must be exactly the keys of that subset.

[▲ back to Index](#table-of-contents)
___

### Modifying keys in a Map

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ Sometimes we need to update the format of a ``Map``, replacing the name given to a key but keeping the new key name associated with the original value. Instead of using ``Map.get/2``, ``Map.put/2``, and ``Map.delete/2`` functions together, which involves a lot of manual work and generates many lines of code, we can simply use the built-in ``Map.new/2`` function along with the use of multi-clause lambdas. This refactoring can significantly reduce the volume of lines of code, eliminating duplicated code and even making the code more resilient to typing-related errors.

* __Examples:__ In the following code, we have a variable `pickup` bound to a `Map`.

```elixir
pickup = %{
"stopName" => "RECEPTION",
"pickupId" => 4018,
"longitude" => 2.360982,
"latitude" => 48.868502
}
```

Let's suppose we want to change the name of the key `"latitude"` to simply `"lat"`, while keeping the rest of the `Map` unchanged. The following code, before refactoring, performs this task manually. It first retrieves the value associated with the `"latitude"` key, then creates a new key called `"lat"` and associates it with the extracted value from the `"latitude"` key. Finally, the `"latitude"` key is removed from the `Map`.

```elixir
# Before refactoring:

latitude = Map.get(pickup, "latitude") # --> step 1
pickup = Map.put(pickup, "lat", latitude) # --> step 2
pickup = Map.delete(pickup, "latitude") # --> step 3
```

Although this solution works, imagine a situation where many keys need to be updated in a `Map`. The manual strategy presented above can become cumbersome and impractical. By using the built-in `Map.new/2` function, this refactoring would make it easier to simultaneously update the format of all keys in the `Map`, as shown in the following code.

```elixir
# After refactoring:

pickup =
Map.new(pickup, fn
{"latitude", lat} -> {"lat", lat}
{key, value} -> {key, value} # <-- Clause for unchanged keys
end)
```

This example is based on an original code by Malreddy Ankanna. Source: [link](https://medium.com/blackode/elixir-code-refactoring-techniques-33589ac56231)

* __Side-conditions:__
* To be eligible for this refactoring, the code snippet must originally be composed of a call to the function `Map.get/2`, followed by `Map.put/2`, and `Map.delete/2`;

* All temporary variables created in the refactored version for performing pattern matching in clauses of the multi-clause anonymous function (*e.g.*, `lat`, `key`, and `value`) must have names different from other previously defined variables, thus avoiding conflicts;

* The multi-clause anonymous function passed as a parameter to the `Map.new/2` call in the refactored version must have at least two clauses: one for each modified key (*e.g.*, `{"latitude", lat} -> {"lat", lat}`) and another to keep all other keys unchanged as in the original (*i.e.*, `{key, value} -> {key, value}`).

[▲ back to Index](#table-of-contents)
___

### Simplifying Ecto schema fields validation

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ After defining a schema in Ecto, it's common to need to group fields for validations, such as those performed by the Ecto validator ``validate_required/3``. However, if we attempt to perform this grouping by manually implementing a list, there's a risk of making the code overly verbose, prone to typographical errors, and even subject to rework if the schema is modified in the future. Instead of relying on manually created lists, we can simply use the Ecto ``__schema__/1`` function, which returns the list of fields in the schema. With this refactoring, we can simplify the code, making it less prone to errors and more maintainable.

* __Examples:__ In the following code, we have an Ecto schema composed by six fields.

```elixir
embedded_schema do
field :carrier_time, :string
field :carrier_date, :string
field :carrier_name, :string
field :carrier_number, :string
field :carrier_terminal, :string
field :carrier_type, :string
end
```

The following code manually lists in the `schema_fields` variable all the fields in our schema that will be validated by the Ecto `validate_required/3` function. Note that this listing process can be cumbersome, prone to typographical errors, and furthermore, it generates duplicated code.

```elixir
# Before refactoring:

def changeset(attrs) do
# Manual listing of schema fields
schema_fields = [:carrier_time, :carrier_date, :carrier_name, :carrier_number, :carrier_terminal, :carrier_type]

%__MODULE__{}
|> cast(attrs, schema_fields)
|> validate_required(schema_fields, message: "Missing Field")
end
```

We can refactor the field listing by replacing the manual list with a call to the Ecto `__schema__/1` function. When we call this function with the atom `:fields` as a parameter, it returns the list of all non-virtual field names, which is exactly the same list we created manually before the refactoring.

```elixir
# After refactoring:

def changeset(attrs) do

schema_fields = __schema__(:fields) #<-- returns dynamically the list of schema fields!

%__MODULE__{}
|> cast(attrs, schema_fields)
|> validate_required(schema_fields, message: "Missing Field")
end
```

Although simple, this refactoring brings many improvements to the code quality. If the database schema is altered, for instance, the above code will continue to work for all fields in the schema without the need for additional modifications.

This example is based on an original code by Malreddy Ankanna. Source: [link](https://medium.com/blackode/elixir-code-refactoring-techniques-33589ac56231)

* __Side-conditions:__
* To be eligible for this refactoring, the code snippet must originally contain a manually created list being passed as a parameter to a call to the `validate_required/3` function;

* If the original list does not contain all the fields of an Ecto schema, the refactored version should perform a list subtraction (*i.e.*, ``Kernel.--/2``) on the result of the `__schema__/1` function call. For example, if the original list includes all fields except `:carrier_terminal` and `:carrier_type`, to maintain the same behavior, the following expression should be used: `__schema__(:fields) -- [:carrier_terminal, :carrier_type]`.

[▲ back to Index](#table-of-contents)
___

### Pipeline using "with"

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ When conditional statements, such as `if..else` and `case`, are used in a nested manner to create sequences of function calls, the code can become confusing and have poor readability. In these situations, we can replace the use of nested conditionals with a kind of function call pipeline using a `with` statement. This refactoring enforces the use of pattern matching at each function call, interrupting the pipeline if any pattern does not match. Additionally, it has the potential to enhance code readability without modifying the signatures (heads) of the involved functions, making this refactoring less prone to breaking changes compared to [Convert nested conditionals to pipeline](#convert-nested-conditionals-to-pipeline).

* __Examples:__ In the following code, the function `update_game_state/3` uses nested conditional statements to control the flow of a sequence of function calls to `valid_move/2`, `players_turn/2`, and `play_turn/3`. All these sequentially called functions have a return pattern of `{:ok, _}` or `{:error, _}`, which is common in Elixir code.

```elixir
# Before refactoring:

defp update_game_state(%{status: :started} = state, index, user_id) do
{move, _} = valid_move(state, index)
if move == :ok do
players_turn(state, user_id)
|> case do
{:ok, marker} -> play_turn(state, index, marker)
other -> other
end
else
{:error, :invalid_move}
end
end
```

Note that, although this code works perfectly, the nesting of conditionals used to ensure the safe invocation of the next function in the sequence makes the code confusing. Therefore, we can refactor it by replacing these nested conditional statements with a pipeline that uses a `with` statement, thereby reducing the number of lines of code and improving readability, while keeping the behavior and signature of all the involved functions intact.

```elixir
# After refactoring:

defp update_game_state(%{status: :started} = state, index, user_id) do
with {:ok, _} <- valid_move(state, index),
{:ok, marker} <- players_turn(state, user_id),
{:ok, new_state} <- play_turn(state, index, marker) do
{:ok, new_state}
else
(other -> other)
end
end
```

As is characteristic of the `with` statement, the next function in this pipeline will only be called if the pattern of the previous call matches. Otherwise, the pipeline is terminated, returning the error that prevented it from proceeding to completion. Note that this refactored version, although functioning correctly, also presents an opportunity to apply the refactoring [Remove redundant last clause in "with"](#remove-redundant-last-clause-in-with), since the last clause of the `with` statement is composed of a pattern identical to the predefined value to be returned by the `with` in case all checked patterns match.

This example is based on an original code by Gary Rennie. Source: [link](https://www.youtube.com/watch?v=V21DAKtY31Q)

* __Side-conditions:__
* To be eligible for this refactoring, each of the functions called sequentially within a nested conditional must originally have their execution flow controlled by some form of pattern matching. For example, functions that return values in the format `{:ok, _}` or `{:error, _}` are candidates for having their sequential calls refactored;

[▲ back to Index](#table-of-contents)
___

### Pipeline for database transactions

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ The `Ecto.Repo.transaction/2` function allows performing operations on the database, such as update and delete. The first parameter of this function can be an anonymous function or a data structure called `Ecto.Multi`. When we want to perform a sequence of operations on the database using only one call to `Ecto.Repo.transaction/2`, the use of an anonymous function as the first parameter of this function can impair code readability, making it confusing. This refactoring converts anonymous functions used to create a pipeline of operations into calls to `Ecto.Repo.transaction/2`, transforming them into instances of `Ecto.Multi`, a data structure used for grouping multiple Repo operations. The code generated by this refactoring becomes cleaner and, furthermore, it does not allow the execution of operations if the `Ecto.Multi` is invalid (i.e., if any of the changesets have errors).

* __Examples:__ In the following code, the function `clear_challenges/2` makes a call to `Ecto.Repo.transaction/2` aiming to execute a sequence of update and delete operations on the database.

```elixir
# Before refactoring:

def update_refused_challenges(user, count) do
params = %{refused_challenges: user.refused_challenges + count}

user
|> User.update_changeset(params)
|> Repo.update()
end

defp delete_challenges(challenges) do
ids = Enum.map(challenges, &(&1.id))
query = where(Challenge, [c], c.id in ^ids)
Repo.delete_all(query)
end

defp stop_games(challenges) do
Enum.map(challenges, &GameRegistry.delete_game(&1.id))
end

def clear_challenges(user, age \\ 300) do
challenges = get_old_open_challenges(user, age)
count = length(challenges)

Repo.transaction(fn ->
with {:ok, user} <- update_refused_challenges(user, count),
delete_challenges(challenges),
stop_games(challenges),
do: user,
else: ({:error, reason} -> Repo.rollback(reason))
end)
end
```

Note that before the refactoring, this call to `Ecto.Repo.transaction/2` uses a complex anonymous function as its first parameter. This anonymous function employs a `with` statement to structure a pipeline of operations, similar to [Pipeline using "with"](#pipeline-using-with). While this code works perfectly, in this context, we can enhance the readability of this database operations pipeline by replacing the anonymous function with the `Ecto.Multi` data structure, specifically designed for creating such pipelines. The following code presents the refactored version of the `clear_challenges/2` function.

```elixir
# After refactoring:

def update_refused_challenges(user, count) do
params = %{refused_challenges: user.refused_challenges + count}

user
|> User.update_changeset(params)
#|> Repo.update() <-- removed during refactoring!
end

defp delete_challenges(challenges) do
ids = Enum.map(challenges, &(&1.id))
query = where(Challenge, [c], c.id in ^ids)
# Repo.delete_all(query) <-- removed during refactoring!
end

defp stop_games(challenges) do
Enum.map(challenges, &GameRegistry.delete_game(&1.id))
{:ok, :stopped_games} # <--- added during refactoring!
end

def clear_challenges(user, age \\ 300) do
challenges = get_old_open_challenges(user, age)
count = length(challenges)

Ecto.Multi.new()
|> Ecto.Multi.update(:user, update_refused_challenges(user, count))
|> Ecto.Multi.delete_all(:challenges, delete_challenges(challenges))
|> Ecto.Multi.run(:games, fn _ -> stop_games(challenges) end)
|> Repo.transaction()
end
```

This example is based on an original code by Gary Rennie. Source: [link](https://www.youtube.com/watch?v=V21DAKtY31Q)

[▲ back to Index](#table-of-contents)
___

### Transform nested "if" statements into a "cond"

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ While code using nested ``if`` statements works, it can be verbose and not very maintainable in some situations. Elixir doesn’t have an ``else if`` construct, but it does have a statement called ``cond`` that is logically equivalent. This refactoring aims to transform multiple conditionals, implemented using nested ``if`` statements, into the use of a ``cond`` statement, leaving the code without complex indentations and therefore cleaner and more readable.

* __Examples:__ In the following code, the `classify_bmi/2` function uses several nested `if..else` statements to classify the Body Mass Index (BMI) of an individual, calculated based on their weight and height.

```elixir
# Before refactoring:

def classify_bmi(weight, height) do
{status, bmi} = calculate_bmi(weight, height)

if status == :ok do
if bmi < 18.5 do
"Underweight"
else
if bmi < 25.0 do
"Normal weight"
else
if bmi < 30.0 do
"Overweight"
else
if bmi < 35.0 do
"Obesity grade 1"
else
if bmi < 40.0 do
"Obesity grade 2"
else
"Obesity grade 3"
end
end
end
end
end
else
"Error in BMI calculation: #{bmi}"
end
end
```

Although this code works well, it is unnecessarily large in terms of the number of lines, and it also has complex indentations, resulting in an unattractive and less maintainable appearance. In the following code, after refactoring the nested `if..else` statements into an Elixir `cond` statement, the `classify_bmi/2` function has a cleaner and more readable appearance.

```elixir
# After refactoring:

def classify_bmi(weight, height) do
{status, bmi} = calculate_bmi(weight, height)

if status == :ok do
cond do
bmi < 18.5 -> "Underweight"
bmi < 25.0 -> "Normal weight"
bmi < 30.0 -> "Overweight"
bmi < 35.0 -> "Obesity grade 1"
bmi < 40.0 -> "Obesity grade 2"
true -> "Obesity grade 3"
end
else
"Error in BMI calculation: #{bmi}"
end
end
```

[▲ back to Index](#table-of-contents)
___

### Explicit a double boolean negation

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ In Elixir, when we perform a double boolean negation, we cast anything truthy to ``true`` and anything non-truthy to ``false``. In other words, this will return ``false`` for ``false`` and ``nil``, and ``true`` for anything else. Although this approach may seem interesting initially, it can make the code less expressive by omitting the real intention of this operation. Therefore, to improve readability, we can replace double boolean negations by introducing a helper multi-clause function.

* __Examples:__ In the following code, we can observe the behavior of double boolean negations applied to four distinct variables.

```elixir
# Before refactoring:

var_1 = true
var_2 = false
var_3 = nil
var_4 = 100

#...Use examples...
iex(1)> !!var_1
true
iex(2)> !!var_2
false
iex(3)> !!var_3
false
iex(4)> !!var_4
true
```

To make our code more expressive, we can refactor the operations above by creating a multi-clause function that uses pattern matching to map all the behavioral possibilities of a double boolean negation. Below, we demonstrate this refactoring by creating the function `helper/1`. Note that this name is purely illustrative, so the function could be renamed to something that better represents its purpose, depending on the context.

```elixir
# After refactoring:

defmodule Foo do
def helper(nil), do: false
def helper(false), do: false
def helper(_), do: true
end

#...Use examples...
iex(1)> Foo.helper(var_1)
true
iex(2)> Foo.helper(var_2)
false
iex(3)> Foo.helper(var_3)
false
iex(4)> Foo.helper(var_4)
true
```

These examples are based on code written in Credo's official documentation. Source: [link](https://hexdocs.pm/credo/Credo.Check.Refactor.DoubleBooleanNegation.html)

* __Side-conditions:__
* The name and arity of function created in this refactoring (*e.g.*, ``helper/1``) must not conflict with the name of any other function already defined or imported by the refactored module.

[▲ back to Index](#table-of-contents)
___

### Transform "if" statements using pattern matching into a "case"

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ Pattern matching is most effective for simple assignments within ``if`` and ``unless`` clauses. Although Elixir allows pattern matching in conditional tests performed by an ``if`` statement, it may compromise code readability when used for flow control purposes. If you need to match a condition and execute a different block when it's not met, it's advisable to use a ``case`` statement instead of combining pattern matching with an ``if`` statement. This refactoring, therefore, aims to carry out this type of code transformation.

* __Examples:__ In the following code, an `if` statement is used in conjunction with pattern matching. In this situation, the `do_something/1` function is called if the pattern matches.

```elixir
# Before refactoring:

if {:ok, contents} = File.read("foo.txt") do
do_something(contents)
end
```

As shown in the following code, we can refactor the previous code by replacing `if` statements that use pattern matching with an Elixir `case` statement, which is a more appropriate conditional for working alongside pattern matching. This refactoring also makes the code more flexible for future changes, as it opens the possibility to execute different code blocks when a pattern does not match, something that would not be possible using only an `if..else` statement.

```elixir
# After refactoring:

case File.read("foo.txt") do
{:ok, contents} -> do_something(contents)
_ -> do_something_else()
end
```

These examples are based on code written in Credo's official documentation. Source: [link](https://hexdocs.pm/credo/Credo.Check.Refactor.MatchInCondition.html)

* __Side-conditions:__
* This refactoring is free of side-conditions and can therefore be applied whenever an `if` statement performing pattern matching in its condition is selected.

[▲ back to Index](#table-of-contents)
___

### Moving "with" clauses without pattern matching

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Grey Literature Review (GLR).

* __Motivation:__ Using ``with`` statements is recommended when you want to string together a series of pattern matches, stopping at the first one that fails. Although is possible to define a ``with`` statement using an initial or final clause that doesn't involve a ``<-`` operator (i.e., it doesn't match anything), it fails to leverage the advantages provided by the ``with``, potentially causing confusion. This refactoring aims to move these clauses that don't match anything to outside the ``with`` statement (for the initial ones) or place them inside the body of the ``with`` statement (for the final ones), thereby enhancing the code's focus and readability.

* __Examples:__ In the following code, we have a `with` statement composed of four clauses. As we can observe, the first and last clauses do not involve matching specific patterns. In other words, they do not use the `<-` operator.

```elixir
# Before refactoring:

with ref = make_ref(),
{:ok, user} <- User.create(ref),
:ok <- send_email(user),
Logger.debug("Created user: #{inspect(user)}") do
user
end
```

To enhance the readability of our code, keeping the clauses of the ``with`` statement focused solely on performing a pipeline of pattern matching, we can move the first clause of this code outside of the ``with`` statement and the last clause to inside its body, as shown in the following code. Note that although these clauses have been moved, the behavior of the code remains unchanged.

```elixir
# After refactoring:

ref = make_ref() # moved outside of the 'with'

with {:ok, user} <- User.create(ref),
:ok <- send_email(user) do
Logger.debug("Created user: #{inspect(user)}") # moved inside the body of the 'with'
user
end
```

These examples are based on code written in Credo's official documentation. Source: [link](https://hexdocs.pm/credo/Credo.Check.Refactor.WithClauses.html)

* __Side-conditions:__
* The first and/or last clause of the `with` statement to be refactored should not use the `<-` operator (*i.e.*, they don't match anything).

[▲ back to Index](#table-of-contents)
___

### Remove redundant last clause in "with"

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Mining Software Repositories (MSR) study.

* __Motivation:__ When the last clause of an ``with`` statement is composed of a pattern identical to the predefined value to be returned by the ``with`` in case all checked patterns match, this clause is considered *redundant*. In such situations, this last clause of the ``with`` can be removed, and the predefined value to be returned by the ``with`` should then be replaced by the expression that was checked in the redundant clause that was removed. This refactoring will maintain the same behavior of the code while making it less verbose and more readable.

* __Examples:__ In the following code, the callback `handle_call/3` uses a `with` statement with a redundant last clause. Note that the pattern compared in the last clause is identical to the predefined value to be returned by the `with` in case all checked patterns match: `{:ok, conf}`.

```elixir
# Before refactoring:

defmodule Phoenix.LiveView.Channel do
use GenServer
...

@impl true
def handle_call({@prefix, :fetch_upload_config, name, cid}, _from, state) do
read_socket(state, cid, fn socket, _ ->
result =
with {:ok, uploads} <- Map.fetch(socket.assigns, :uploads),
{:ok, conf} <- Map.fetch(uploads, name) do #<- redundant last clause!
{:ok, conf} #<- predefined value to be returned by the ``with``!
end

{:reply, result, state}
end)
end
...
end
```

As demonstrated in the following code, we can refactor this by removing the redundant last clause `{:ok, conf} <- Map.fetch(uploads, name)` and also replacing the predefined value to be returned with the expression `Map.fetch(uploads, name)`, which was previously checked in the removed redundant clause.

```elixir
# After refactoring:

defmodule Phoenix.LiveView.Channel do
use GenServer
...

@impl true
def handle_call({@prefix, :fetch_upload_config, name, cid}, _from, state) do
read_socket(state, cid, fn socket, _ ->
result =
with {:ok, uploads} <- Map.fetch(socket.assigns, :uploads) do
Map.fetch(uploads, name) #<- predefined value to be returned by the ``with``!
end

{:reply, result, state}
end)
end
...
end
```

This example is based on an original code refactored by ByeongUk Choi. Source: [link](https://github.com/phoenixframework/phoenix_live_view/pull/1958)

* __Side-conditions:__
* The pattern checked in the last clause of the `with` statement must be lexically identical to the value returned in the body of the `with`. Additionally, the body of the `with` should contain only the value to be returned.

[▲ back to Index](#table-of-contents)
___

### Replace "Enum" collections with "Stream"

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Mining Software Repositories (MSR) study.

* __Motivation:__ All the functions in the ``Enum`` module are __*eager*__. This means that when performing multiple operations with ``Enum``, each operation will generate an intermediate collection (e.g., ``lists`` or ``maps``) until we reach the result. On the other hand, Elixir provides the ``Stream`` module which supports __*lazy operations*__, so instead of generating intermediate collections, streams build a series of computations that are invoked only when we pass the underlying ``Stream`` to the ``Enum`` module. This refactoring suggests using the ``Stream`` module instead of the ``Enum`` module __*when multiple operations in large collections are performed together*__. This can significantly decrease the time to traverse the collections while keeping the same behavior.

* __Examples:__ The code examples below illustrate this refactoring. Before the refactoring, the higher-order function ``sum_odd_numbers/2`` uses only ``Enum``'s functions to initially modify the values of a ``list``, filter all modified values that are odd, and then sum them up.

```elixir
# Before refactoring:

defmodule Foo do
def sum_odd_numbers(list, odd?) do
list
|> Enum.map(&(&1 * 3))
|> Enum.filter(odd?)
|> Enum.sum()
end
end

#...Use examples...
iex(1)> Foo.sum_odd_numbers([1,2,3,4,5,6,7,8], &(rem(&1,2) != 0))
48
```

Following the refactoring, ``sum_odd_numbers/2`` retains the same behavior but now uses some ``Stream`` functions instead of ``Enum``. Note that even after the refactoring, the `Enum.sum/1` function, which is the last operation in the pipeline, was kept in the code. Since `Stream` module functions are __*lazy operations*__, the computations accumulated in `Stream.map/2` and `Stream.filter/2` are only invoked when this `Stream` is passed to a function from the `Enum` module, in this case the `Enum.sum/1` function.

```elixir
# After refactoring:

defmodule Foo do
def sum_odd_numbers(list, odd?) do
list
|> Stream.map(&(&1 * 3)) #<- Replace "Enum" with "Stream"!
|> Stream.filter(odd?) #<- Replace "Enum" with "Stream"!
|> Enum.sum()
end
end

#...Use examples...
iex(1)> Foo.sum_odd_numbers([1,2,3,4,5,6,7,8], &(rem(&1,2) != 0))
48
```

By using the [Benchee](https://github.com/bencheeorg/benchee) library for conducting micro benchmarking in Elixir, we can highlight the performance improvement potential of this refactoring. In the following code, the `sum_odd_numbers/2` function is given illustrative names, `before_ref/1` and `after_ref/1`, to represent their respective `Enum` and `Stream` versions.

```elixir
list = Enum.to_list(1..50_000_000)
odd? = fn x -> rem(x, 2) != 0 end

Benchee.run(%{
"enum" => fn -> Foo.before_ref(list, odd?) end,
"stream" => fn -> Foo.after_ref(list, odd?) end
}, parallel: 4, memory_time: 2)
```

Note that for a list with fifty million elements, the `Stream` version, although it consumes more memory, can be about __*twelve times faster*__ than the `Enum` version.

```bash
Operating System: Windows
CPU Information: Intel(R) Core(TM) i7-2670QM CPU @ 2.20GHz
Number of Available Cores: 8
Available memory: 11.95 GB
Elixir 1.16.0
Erlang 26.2.1

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 2 s
reduction time: 0 ns
parallel: 4
inputs: none specified
Estimated total run time: 18 s

Benchmarking enum ...
Benchmarking stream ...

Name ips average deviation median 99th %
stream 0.144 0.116 min ±1.63% 0.116 min 0.117 min
enum 0.0123 1.36 min ±49.35% 1.11 min 2.31 min

Comparison:
stream 0.144
enum 0.0123 - 11.76x slower +1.24 min

Memory usage statistics:

Name Memory usage
stream 2.05 GB
enum 1.12 GB - 0.55x memory usage -0.93132 GB
```

These examples are based on code written in Elixir's official documentation. Source: [link](https://hexdocs.pm/elixir/enumerable-and-streams.html)

* __Side-conditions:__
* Function calls from the `Enum` module used in a pipeline can only be replaced by functions from the `Stream` module that perform operations equivalent to the originals;

* To maintain the behavior of the original code, after the calls to functions from the `Stream` module inserted in this refactoring, there must be at least one call to a function from the `Enum` module in the pipeline.

[▲ back to Index](#table-of-contents)
___

### Generalise a process abstraction

* __Category:__ Elixir-specific Refactorings.

* __Source:__ This refactoring emerged from a Mining Software Repositories (MSR) study.

* __Motivation:__ Elixir provides different types of process abstractions for distinct purposes. While the `Task` and `Agent` abstractions have very specific purposes, `GenServer` is a more generic process abstraction, therefore having the capability to do everything that `Task` and `Agent` can do, as well as having additional capabilities beyond these two specific abstractions. This refactoring aims to transform `Task` or `Agent` abstractions into `GenServer` when these specific-purpose abstractions are used beyond their suggested purposes. More specifically, this refactoring can be used to remove the code smell [GenServer Envy](https://github.com/lucasvegi/Elixir-Code-Smells?#genserver-envy). By using an appropriate process abstraction for the purpose of the code, we can even improve its readability.

* __Examples:__ In the following code, the `DatabaseServer` module makes use of a `Task` abstraction to provide its clients with the ability to query a database using the interface function `get/2`. As can be observed in this example, this `Task` __*behaves like a long-running server process*__, frequently communicating with other client processes. This behavior is very different from the suggested purpose for `Tasks`, which typically should only perform a particular operation during their lifetime and then stop upon the completion of that operation without communication with other processes.

```elixir
# Before refactoring:

defmodule DatabaseServer do
use Task

def start_link() do
Task.start_link(&loop/0)
end

defp loop() do
receive do
{:run_query, caller, query_def} ->
send(caller, {:query_result, run_query(query_def)})
end
loop()
end

def get(server_pid, query_def) do
send(server_pid, {:run_query, self(), query_def})
receive do
{:query_result, result} -> result
end
end

defp run_query(query_def) do
Process.sleep(1000)
"#{query_def} result"
end
end

#...Use examples...
iex(1)> {:ok, pid} = DatabaseServer.start_link()
{:ok, #PID<0.161.0>}
iex(2)> DatabaseServer.get(pid, "query 1")
"query 1 result"
iex(3)> DatabaseServer.get(pid, "query 2")
"query 2 result"
```

Considering that the above code represents an instance of the code smell [GenServer Envy](https://github.com/lucasvegi/Elixir-Code-Smells?#genserver-envy), we can refactor it by generalizing the process abstraction used. In other words, we can transform this specific process abstraction (`Task`) into a generic process abstraction (`GenServer`). Note that although the process abstraction used has been replaced, the behavior of the code remains the same because the interfaces of the public functions have not been modified. Furthermore, the readability of the refactored code has improved, as it was no longer necessary to make explicit message passing and implement recursive functions to keep the process alive.

```elixir
# After refactoring:

defmodule DatabaseServer do
use GenServer

def start_link() do
GenServer.start_link(__MODULE__, nil)
end

def get(server_pid, query_def) do
GenServer.call(server_pid,{:run_query, query_def})
end

defp run_query(query_def) do
Process.sleep(1000)
"#{query_def} result"
end

@impl
def handle_call({:run_query, query_def}, _, state) do
{:reply, run_query(query_def), state}
end
end

#...Use examples...
iex(1)> {:ok, pid} = DatabaseServer.start_link()
{:ok, #PID<0.164.0>}
iex(2)> DatabaseServer.get(pid, "query 1")
"query 1 result"
iex(3)> DatabaseServer.get(pid, "query 2")
"query 2 result"
```

This example is based on an original code by Saša Jurić available in the __"Elixir in Action, 2. ed."__ book.

[▲ back to Index](#table-of-contents)
___

## Traditional Refactorings

Traditional refactorings are those mainly based on Fowler's catalog or that use programming features independent of languages or paradigms. In this section, 25 different refactorings classified as traditional are explained and exemplified:

### Rename an identifier

* __Category:__ Traditional Refactorings.

* __Motivation:__ It's important to keep in mind that although giving good names to things may not be a simple task, good names for code structures are essential to facilitate maintenance activities promoted by humans. When the name of an identifier does not clearly convey its purpose, it should be renamed to improve the code's readability, thus avoiding a developer from wasting too much time trying to understand code developed by someone else or even developed by themselves a long time ago. In Elixir, code identifiers can be ``functions``, ``modules``, ``macros``, ``variables``, ``map/struct fields``, registered processes (e.g. ``GenServer``), ``protocols``, ``behaviours callbacks``, ``module aliases``, ``module attributes``, ``function parameters``, etc.

* __Examples:__ The following code illustrates this refactoring in the context of ``renaming functions``. Before the refactoring, we have a function ``foo/2``, which receives two parameters and returns their sum. Although it is a simple function, it is evident that its name does not clearly convey its purpose.

```elixir
# Before refactoring:

def foo(value_1, value_2) do
value_1 + value_2
end
```

We intend to rename this function to ``sum/2``, thus highlighting its purpose. To do so, we should create a new function with this name and copy the body of the ``foo/2`` function to it. Additionally, the body of the ``foo/2`` function should be replaced by a call to the new ``sum/2`` function:

```elixir
# After refactoring:

def sum(value_1, value_2) do
value_1 + value_2
end

def foo(value_1, value_2) do #<-- must be deleted in the future!
sum(value_1, value_2)
end
```

The ``foo/2`` function acts as a wrapper that calls ``sum/2`` and should be kept in the code temporarily, only while the calls to it throughout the codebase are gradually replaced by calls to the new ``sum/2`` function. This mitigates the risk of this refactoring generating breaking changes. When there are no more calls to the ``foo/2``, it should be deleted from its module.

* __Side-conditions:__
* The new name should not conflict with other pre-existing names;

* In the specific case of ``renaming functions``, the new function name should not conflict with other functions of the same module, nor with those imported from another module.

* __Mechanics:__ This sequence of steps may vary depending on the type of identifier that will be renamed. In the specific case of ``renaming functions``, the sequence of steps for the transformation should be as follows.

* Check if the function being renamed was not previously defined by an Elixir ``behaviour`` or ``protocol`` implemented by the module of the function;
* If the name was originally defined in a ``behaviour`` or ``protocol``, these transformations should be promoted at the source of that function (``behaviour`` or ``protocol``) and in all modules of the codebase that implement that source.

* Create a new function with a name that better indicates its purpose and copy the body of the original function (with a bad name) into the new function;

* Replace the body of the original function with a call to the new function;

* Test your code to check for the occurrence of breaking changes;

* For each call to the original function, replace it with a call to the new renamed function and test your code again;

* After all calls to the original function have been replaced with the new function, and the code has been tested to verify that there are no breaking changes, it is safe to delete the original function and its definitions in a ``behaviour`` or ``protocol`` (if applicable) to complete the refactoring process.

[▲ back to Index](#table-of-contents)
___

### Moving a definition

* __Category:__ Traditional Refactoring.

* __Motivation:__ Modules in Elixir are used to group related and interdependent definitions, promoting cohesion. A definition in Elixir can be a ``function``, ``macro``, or ``struct``, for example. When a definition accesses more data or calls more functions from another module other than its own, or is used more frequently by another module, we may have less cohesive modules with high coupling. To improve maintainability by grouping more cohesive definitions in modules, these definitions should be moved between modules when identified. This refactoring helps to eliminate the [Feature Envy][Feature Envy] code smell.

* __Examples:__ The following code illustrates this refactoring in the context of ``moving functions``. Before the refactoring, we have a function ``foo/2`` from ``ModuleA``, which besides not being called by any other function in its module, only makes calls to functions from another module (``ModuleB``). This function ``foo/2``, as it is clearly misplaced in ``ModuleA``, decreases the cohesion of this module and creates an avoidable coupling with ``ModuleB``, making the codebase harder to maintain.

```elixir
# Before refactoring:

defmodule ModuleA do
alias ModuleB, as: B

def foo(v1, v2) do
B.baz(v1, v2)
|> B.qux()
end

def bar(v1) do
...
end
end

#...Use example...
iex(1)> ModuleA.foo(1, 2)
```

```elixir
# Before refactoring:

defmodule ModuleB do
def baz(value_1, value_2) do
...
end

def qux(value_1) do
...
end
end
```

We want to move ``foo/2`` to ``ModuleB`` to improve the grouping of related functions in our codebase. To do this, we should not only copy ``foo/2`` to ``ModuleB``, but also check if ``foo/2`` depends on other resources that should also be moved or if it has references that need to be updated when the function is positioned in its new module.

```elixir
# After refactoring:

defmodule ModuleA do
def bar(v1) do
...
end
end
```

```elixir
# After refactoring:

defmodule ModuleB do
def baz(value_1, value_2) do
...
end

def qux(value_1) do
...
end

def foo(v1, v2) do #<-- moved function!
baz(v1, v2)
|> qux()
end
end

#...Use example...
iex(1)> ModuleB.foo(1, 2)
```

All calls to ``ModuleA.foo/2`` should be updated to ``ModuleB.foo/2``. When there are no more calls to ``ModuleA.foo/2`` in the codebase, it should be deleted from ``ModuleA``. In addition, ``ModuleA`` will no longer need to import functions from ``ModuleB``, since this coupling has been undone.

* __Side-conditions:__
* When the moved definition is a ``function`` or ``macro``, the name of this definition must not conflict with the name of any other definition of the same type already defined in the target module or imported by it;

* When the moved definition is a ``function`` that originally calls other functions or macros, after the refactoring, this moved function must still refer to the same definitions of functions and macros originally called;

* When the moved definition is a ``struct``, it can only be moved to a target module that does not already define another ``struct``.

These side conditions are based on definitions written by László Lövei *et al.* in this paper: [[1]](https://doi.org/10.1145/1411273.1411285)

[▲ back to Index](#table-of-contents)
___

### Add or remove a parameter

* __Category:__ Traditional Refactorings.

* __Motivation:__ This refactoring is used when it is necessary to request additional information from the callers of a function or the opposite situation, when some information passed by the callers is no longer necessary. The transformation promoted by this refactoring usually creates a new function with the same name as the original, but with a new parameter added or a parameter removed, and the body of the original function is replaced by a call to the new function, subsequently replacing the calls to the original function with calls to the new function. Thanks to the possibility of specifying default values for function parameters in Elixir, using the ``\\`` operator, we can simplify the mechanics of this refactoring, as shown in the following example.

* __Examples:__ The following code has a ``foo/1`` function that always sum the constant +1 to the ``value`` passed as a parameter.

```elixir
# Before refactoring:

def foo(value) do
value + 1
end
```

We want to add a parameter to the function ``foo/1`` to generalize the constant used in the sum. To do this, we can add ``new_arg`` at the end of the parameter list, accompanied by the default value ``\\ 1``. In addition, we should modify the body of the function to use this new parameter, as shown below.

```elixir
# After refactoring:

def foo(value, new_arg \\ 1) do
value + new_arg
end
```

Note that although we have now only explicitly implemented the ``foo/2`` function, in Elixir this definition generates two functions with the same name, but with different arities: ``foo/1`` and ``foo/2``. This will allow the callers of the original function to continue functioning without any changes. Although the example has only emphasized the addition of new parameters using default values, this feature can also be useful when we want to remove a parameter from a function, decreasing its arity. We can define a default value for the parameter to be removed when it is no longer used in the body of the function. This will keep the higher arity function callers working, even if providing an unused additional value. Additionally, new callers of the lower arity function can coexist in the codebase. When all old callers of the higher arity function are replaced by calls to the lower arity function, the parameter with the default value can finally be removed from the function without compromising any caller.

* __Side-conditions:__
* When adding a new parameter, its name (*e.g.*, `new_arg`) must not conflict with the name of any other parameter or local variable in the refactored function;

* When adding a new parameter to a function and thus increasing its arity, this operation must not conflict with functions of the same name and arity that are already defined or imported into the refactored module;

* When removing a parameter, it should not be used in the definition of the function that is being refactored;

* When removing a parameter from a function and thus reducing its arity, this operation must not conflict with functions of the same name and arity that are already defined or imported into the refactored module.

These side conditions are based on definitions provided by members of the HaRe project (Haskell Refactorer tool), as described in the following link: [[1]](https://www.cs.kent.ac.uk/projects/refactor-fp/catalogue/)

[▲ back to Index](#table-of-contents)
___

### Grouping parameters in tuple

* __Category:__ Traditional Refactorings.

* __Motivation:__ This refactoring can be useful to eliminate the [Long Parameter List][Long Parameter List] code smell. When functions have very long parameter lists, their interfaces can become confusing, making the code difficult to read and increasing the propensity for bugs. This refactoring concentrates on grouping a number of a function's sequential and related parameters into a ``tuple``, thereby shortening the list of parameters. The function`s callers are also modified by this refactoring to correspond to the new parameter list. ``Tuple`` is a data type supported by Elixir and is often used to group a fixed number of elements.

* __Examples:__ The following code presents the `Foo` module, composed only by the ``rand/2`` function. This function takes two values as a parameter and returns the random number present in the range defined by the two parameters. Although ``rand/2``'s parameter list is not necessarily long, try to imagine a scenario where a function has a list consisting of five or more parameters, for example. Furthermore, not always all parameters of a function can be grouped as in this example.

```elixir
# Before refactoring:

defmodule Foo do
def rand(first, last) do
Enum.random(first..last)
end
end

#...Use examples...
iex(1)> Foo.rand(1, 9)
4
iex(2)> Foo.rand(2, 8)
2
```

We want to find and group parameters that are related, thus decreasing the size of the list. Note that in this case, the two parameters in the list form an interval, so they are related and can be grouped to compose the function ``rand/1``, as shown below.

```elixir
# After refactoring:

defmodule Foo do
def rand({first, last} = group) do
Enum.random(first..last)
end
end

#...Use examples...
iex(1)> g = {1, 9} #<= tuple definition
iex(2)> Foo.rand(g)
5

iex(3)> g = {2, 8} #<= tuple definition
iex(4)> Foo.rand(g)
7

iex(5)> g = {2, 8, 3} #<= wrong tuple definition!
iex(6)> Foo.rand(g)
** (FunctionClauseError) no function clause matching in Foo.rand/1
```

The function ``rand/1`` performs pattern matching with the value of its single parameter. This, in addition to allowing the extraction of the values that make up the ``tuple``, allows for validating whether the format of the parameter received in the call is really that of the ``tuple`` of the expected length. Also, note that this refactoring updates all function callers to the new parameter list.

__Important:__ Although this refactoring has grouped parameters using ``tuples``, we can find in different functions identical groups of parameters that could be grouped (i.e., Data Clumps). In that case, is better to create a ``struct`` to group these parameters and reuse this ``struct`` to refactor all functions where this group of parameters occurs.

* __Side-conditions:__
* The grouped parameters must be sequential in the original parameter list of the modified function;

* The function created by this refactoring, with reduced arity, must not conflict with any existing functions defined in the same module or imported by it;

* The refactored function must not be an OTP callback function (*e.g.*, ``GenServer.handle_call/3``).

These side conditions are based on definitions written by Huiqing Li *et al.* in this paper: [[1]](https://doi.org/10.1145/1411273.1411283)

[▲ back to Index](#table-of-contents)
___

### Reorder parameter

* __Category:__ Traditional Refactoring.

* __Motivation:__ Although the order of parameters does not change the complexity of executing a code for the machine, when a function has parameters defined in an order that does not group similar semantic concepts, the code can become more confusing for programmers, making it difficult to read and also becoming more prone to errors during its use. When we find functions with poorly organized parameters, we must reorder them in a way that allows for better readability and meaning for programmers.

* __Examples:__ The following code illustrates this refactoring. Before the refactoring, we have a function ``area/3``, responsible for calculating the area of a trapezoid. Although the body of this function is correct, the two bases of the trapezoid are not sequential parameters, so this can confuse a programmer when this function is called. The area of a trapezoid that has ``major_base`` = 24 cm, ``minor_base`` = 9 cm, and ``height`` = 15 cm equals 247.5 cm^2. In the first call of ``area/3`` in the example, the programmer imagined that the values of the bases would be the first two parameters of the function and thus had a calculation error that could easily go unnoticed.

```elixir
# Before refactoring:

def area(major_base, height, minor_base) do
((major_base + minor_base) * height) / 2
end

#...Use examples...
iex(1)> Trapezoid.area(24, 9, 15) #<- misuse
175.5

iex(2)> Trapezoid.area(24, 15, 9)
247.5
```

We want to reorder the parameters of ``area/3`` to make them semantically organized. To do so, we should create a new function ``new_area/3``, which will have the parameters reordered and copy the body of the ``area/3`` to it. Additionally, the body of the ``area/3`` should be replaced by a call to the ``new_area/3``:

```elixir
# After refactoring:

def new_area(major_base, minor_base, height) do #<-- can be renamed in the future!
((major_base + minor_base) * height) / 2
end

def area(major_base, height, minor_base) do #<-- must be deleted in the future!
new_area(major_base, minor_base, height)
end

#...Use examples...
iex(1)> Trapezoid.new_area(24, 9, 15)
247.5

iex(2)> Trapezoid.area(24, 15, 9)
247.5
```

* __Side-conditions:__
* The new function created by this refactoring must have the same arity as the original function and have a name different from all others defined or imported by the refactored module, avoiding conflicts;

* Immediately after the refactoring, there should be no calls to the newly created function (*e.g.*, `new_area/3`) anywhere other than within the body of the original function (*e.g.*, `area/3`).

[▲ back to Index](#table-of-contents)
___

### Extract function

* __Category:__ Traditional Refactoring.

* __Motivation:__ For us to have code with easy readability, it is important that its purpose be clearly exposed, not requiring a developer to spend too much time to understand its purpose. Sometimes we come across functions that concentrate on many purposes and therefore become long ([Long Functions][Long Function]), making their maintenance difficult. It is common in such functions to find code comments used to explain the purpose of a sequence of lines. Whenever we encounter functions with these characteristics, we should extract these code sequences into a new function that has a name that clearly explains its purpose. In the original function, the extracted code block should be replaced by a call to the new function. This refactoring makes functions smaller and more readable, thus facilitating their maintenance.

* __Examples:__ The following code illustrates this refactoring. Before the refactoring, we have a function ``ticket_booking/5``, responsible for booking an airline ticket for a passenger. All the main steps of the booking are done through a sequence of operations chained by pipe operators. After payment confirmation, the booking process is finalized by returning a tuple containing important reservation data that must be informed to the passenger. We can observe that the last 3 lines of the ``ticket_booking/5`` function are responsible for presenting a report. Note that these lines were preceded by a comment attempting to explain their purposes, highlighting that these expressions are misplaced within ``ticket_booking/5`` and even require documentation to help understand the code.

```elixir
# Before refactoring:

def ticket_booking(passenger, air_line, date, credit_card, seat) do
{company, contact_info, cancel_policy} = check_availability(air_line, date)
|> documents_validation(passenger)
|> select_seat(seat)
|> payment(credit_card)
#print booking report
IO.puts("Booking made at the company: #{company}")
IO.puts("Any doubt, contact: #{contact_info}")
IO.puts("For cancellations, see company policies: #{cancel_policy}")
end
```

We want to make this code more concise, reducing the size of ``ticket_booking/5`` and improving its readability. To achieve this, we should create a new function ``report/1`` that will receive a tuple as a parameter, extract the values from the tuple to variables via pattern matching, and finally present the report containing these values. In addition, the body of ``ticket_booking/5`` should be updated to include a call to ``report/1`` to replace the extracted lines of code.

```elixir
# After refactoring:

def report({company, contact_info, cancel_policy} = confirmation) do
IO.puts("Booking made at the company: #{company}")
IO.puts("Any doubt, contact: #{contact_info}")
IO.puts("For cancellations, see company policies: #{cancel_policy}")
end

def ticket_booking(passenger, air_line, date, credit_card, seat) do
check_availability(air_line, date)
|> documents_validation(passenger)
|> select_seat(seat)
|> payment(credit_card)
|> report() #<- extracted function call!
end
```

This refactoring not only improves the readability of ``ticket_booking/5``, but also enables more code reuse, since ``report/1`` may eventually be called by other functions in the codebase.

* __Side-conditions:__
* The name and arity of extracted function created in this refactoring (*e.g.*, `report/1`) must not conflict with the name of any other function already defined or imported by the refactored module;

* The extracted sequence of expressions must not make recursive calls to the original function;

* The extracted sequence of expressions must not be originally included in a ``guard`` sequence;

* The extracted sequence of expressions must not be originally part of a pattern;

* The extracted sequence of expressions must not be originally within a ``macro`` definition.

These side conditions are based on definitions provided by members of the RefactorErl project, as described in the following link: [[1]](http://pnyf.inf.elte.hu/trac/refactorerl/wiki/RefactoringSteps)

[▲ back to Index](#table-of-contents)
___

### Inline function

* __Category:__ Traditional Refactoring.

* __Motivation:__ This refactoring is the inverse of [Extract Function](#extract-function). We typically extract functions to reduce their size, making them more readable and easier to maintain. However, in some situations, the body of a function basically just delegates to the call of another function. In these cases, the purpose of the function body is as clear as its name, and there is no benefit in keeping the declaration of this function. In fact, excessive delegation may create code with very indirect execution flows that are difficult to debug. In these situations, an inline function can be used, replacing all calls to the function with its body, and then getting rid of the function.

* __Examples:__ The following code illustrates this refactoring. Before the refactoring, we have a module called ``Order`` composed of the private function ``sum_list/1`` and the public function ``get_amount/1``. The function ``get_amount/1`` receives a list of items in an order and delegates the sum of all item values to the ``sum_list/1`` function. As we can see, the ``sum_list/1`` function simply calls the ``Enum.sum/1`` function provided natively by Elixir, thus being an example of excessive and unnecessary delegation.

```elixir
# Before refactoring:

defmodule Order do
defp sum_list(list) do
Enum.sum(list)
end

def get_amount(order_itens) do
sum_list(order_itens)
end
end
```

To eliminate the excessive delegation generated by the ``sum_list/1`` function, we will replace all calls to ``sum_list/1`` with its body. Then, we can delete the ``sum_list/1`` function from the ``Order`` module since it will no longer be necessary.

```elixir
# After refactoring:

defmodule Order do
def get_amount(order_itens) do
Enum.sum(order_itens) #<- inlined function!
end
end
```

This refactoring preserves the behavior of the function and will make it easier for the programmer to debug the code.

* __Side-conditions:__
* The body of the original function, which is used to replace its calls, must not contain variables that conflict with the names of other variables already existing in the scope where the function calls occurred;

* If the calls replaced by the body of a function refer to a function defined in a different module, the body of that function must not contain calls to functions that are not imported in the scope where the replaced calls occurred.

These side conditions are based on definitions provided by members of the RefactorErl project, as described in the following link: [[1]](http://pnyf.inf.elte.hu/trac/refactorerl/wiki/RefactoringSteps)

[▲ back to Index](#table-of-contents)
___

### Folding against a function definition

* __Category:__ Traditional Refactorings.

* __Motivation:__ This refactoring can be used in the context of removing [Duplicated Code][Duplicated Code], replacing a set of expressions with a call to an existing function that performs the same processing as the duplicated code. The opportunity to apply this refactoring may occur after the chained execution of the [Extract function](#extract-function) and [Generalise a function definition](#generalise-a-function-definition) refactorings. After generalizing a function that has been previously extracted, it is possible that there may still be some code snippets in the codebase that are duplicated with the generalized function. This refactoring aims to, from a source function, find code that is duplicated in relation to it and replace the duplications with calls to the source function. Some adaptations in these new call points to the source function may be necessary to preserve the code's behavior.

* __Examples:__ The following code exemplifies this refactoring. Before the refactoring, we have a ``Class`` module composed of two functions. The function ``report/1`` was previously extracted from a code snippet not shown in this example. Later, this extracted function was generalized, resulting in its current format. The function ``improve_grades/3`` already existed in the ``Class`` module before ``report/1`` was generated through refactoring. Note that ``improve_grades/3`` has code snippets that are duplicated with ``report/1``.

```elixir
# Before refactoring:

defmodule Class do
defstruct [:id, :grades, :avg, :worst, :best]

def report(list) do #<- Generated after extraction and generalisation!
avg = Enum.sum(list) / length(list)
{min, max} = Enum.min_max(list)
{avg, min, max}
end

def improve_grades(class_id, grades, students_amount) do
high_grade = Enum.max(grades)
adjustment_factor = 100 / high_grade
new_grades = Enum.map(grades, &(&1 * adjustment_factor) |> Float.round(2))

grades_avg = Enum.sum(new_grades) / students_amount #<- duplicated code
{w, b} = Enum.min_max(new_grades) #<- duplicated code

%Class{id: class_id, grades: new_grades, avg: grades_avg, worst: w, best: b}
end
end

#...Use examples...
iex(1)> Class.improve_grades(:software_engineering, [26, 49, 70, 85, 20, 75, 74, 15], 8)
%Class{
id: :software_engineering,
grades: [30.59, 57.65, 82.35, 100.0, 23.53, 88.24, 87.06, 17.65],
avg: 60.88375,
worst: 17.65,
best: 100.0
}
```

We want to eliminate the duplicated code in ``improve_grades/3``. To achieve this, we can replace the duplicated code snippet with a call to ``report/1``. Note that some adaptations to the function call that will replace the duplicated code may be necessary.

```elixir
# After refactoring:

defmodule Class do
defstruct [:id, :grades, :avg, :worst, :best]

def report(list) do
avg = Enum.sum(list) / length(list)
{min, max} = Enum.min_max(list)
{avg, min, max}
end

def improve_grades(class_id, grades, students_amount) do
high_grade = Enum.max(grades)
adjustment_factor = 100 / high_grade
new_grades = Enum.map(grades, &(&1 * adjustment_factor) |> Float.round(2))

{grades_avg, w, b} = report(new_grades) #<- Folding against a function definition!

%Class{id: class_id, grades: new_grades, avg: grades_avg, worst: w, best: b}
end
end

#...Use examples...
iex(1)> Class.improve_grades(:software_engineering, [26, 49, 70, 85, 20, 75, 74, 15], 8)
%Class{
id: :software_engineering,
grades: [30.59, 57.65, 82.35, 100.0, 23.53, 88.24, 87.06, 17.65],
avg: 60.88375,
worst: 17.65,
best: 100.0
}
```

Also note that in this example, after the refactoring is done, the third parameter of the ``improve_grades/3`` function is no longer used in the function body. This is an opportunity to apply the [Add or remove parameter](#add-or-remove-a-parameter) refactoring.

* __Side-conditions:__
* The duplicated code to be replaced and the function to be called to perform this refactoring must be defined in the same module;

* After replacing the duplicated code with a function call, compensations (*e.g.*, pattern matching to extract values returned by the function) may be necessary to maintain the code's original behavior.

These side conditions are based on definitions provided by members of the HaRe project (Haskell Refactorer tool), as described in the following link: [[1]](https://www.cs.kent.ac.uk/projects/refactor-fp/catalogue/)

[▲ back to Index](#table-of-contents)
___

### Extract constant

* __Category:__ Traditional Refactorings.

* __Motivation:__ This refactoring aims to improve code readability and maintainability. When we use meaningless numbers (magic numbers) directly in expressions, code comprehension can become more complex for humans. Additionally, if the same meaningless number is scattered throughout the codebase and needs to be modified in the future, it can generate a significant maintenance burden, increasing the risk of bugs. To improve the code, this refactoring seeks to create a constant with a meaningful name for humans and replace occurrences of the meaningless number with the extracted constant.

* __Examples:__ The following code provides an example of this refactoring. Prior to the refactoring, we had a ``Circle`` module consisting of two functions. Both functions used the magic number ``3.14``. Although this example contains simple code that may not seem to justify the developer's concern with extracting constants, try to imagine a more complex scenario involving larger and non-trivial code that makes more extensive use of these meaningless numbers. This could cause a lot of headache for a developer.

```elixir
# Before refactoring:

defmodule Circle do
def area(r) do
3.14 * r ** 2
end

def circumference(r) do
2 * 3.14 * r
end
end

#...Use examples...
iex(1)> Circle.area(3)
28.26

iex(2)> Circle.circumference(3)
18.84
```

To improve the comprehension of this code and make it easier to maintain, we can create a ``module attribute`` with a human-readable name (``@pi``) and replace the numbers with the use of this attribute.

```elixir
# After refactoring:

defmodule Circle do
@pi 3.14 #<- extracted constant!

def area(r) do
@pi * r ** 2
end

def circumference(r) do
2 * @pi * r
end
end

#...Use examples...
iex(1)> Circle.area(3)
28.26

iex(2)> Circle.circumference(3)
18.84
```

This not only gives meaning to the number but also facilitates maintenance in case it needs to be changed. In the case of ``@pi``, if we wish to improve the precision of the calculations by adding more decimal places to its value, this can be easily done in the refactored code.

[▲ back to Index](#table-of-contents)
___

### Temporary variable elimination

* __Category:__ Traditional Refactorings.

* __Motivation:__ This is a refactoring motivated by the compiler optimization technique known as copy propagation. Copy propagation is a transformation that, for an assignment of the form ``a`` = ``b``, replaces uses of the variable ``a`` with the value of the variable ``b``, thus eliminating redundant computations. This refactoring can be very useful for eliminating temporary variables that are responsible only for storing results to be returned by a function, or even intermediate values used during processing.

* __Examples:__ The following code provides an example of this refactoring. Prior to the refactoring, we have a function ``bar/2`` that takes an integer value ``b`` and a ``list`` as parameters. The function returns a tuple containing two elements, the first of which is the value contained in the index ``c`` of the ``list`` and the second of which is the sum of all elements in a modified version of the ``list``.

```elixir
# Before refactoring:

defmodule Foo do
def bar(b, list) when is_integer(b) do
a = b * 2
c = a
result_1 = Enum.at(list, c)
r = a
result_2 = Enum.map(list, &(&1 + r))
|> Enum.sum()

{result_1, result_2}
end
end

#...Use examples...
iex(1)> Foo.bar(2, [1, 2, 3, 4, 5, 6])
{5, 45}
```

To perform this processing, the code above makes excessive and unnecessary use of temporary variables. As shown below, after the refactoring, these temporary variables will be replaced by their values and subsequently removed when they are no longer used in any location.

```elixir
# After refactoring:

defmodule Foo do
def bar(b, list) when is_integer(b) do
{ Enum.at(list, b * 2),
Enum.map(list, &(&1 + b * 2)) |> Enum.sum() }
end
end

#...Use examples...
iex(1)> Foo.bar(2, [1, 2, 3, 4, 5, 6])
{5, 45}
```

This refactoring can promote a significant simplification of some code, as well as avoid redundant computations that can harm performance.

* __Side-conditions:__
* The variable has only one binding occurrence on the left-hand side of a pattern matching expression and is not part of a compound pattern;

* The expression bound to the variable is pure, meaning it has no side effects.

These side conditions are based on definitions provided by members of the RefactorErl project, as described in the following link: [[1]](http://pnyf.inf.elte.hu/trac/refactorerl/wiki/RefactoringSteps)

[▲ back to Index](#table-of-contents)
___

### Extract expressions

* __Category:__ Traditional Refactorings.

* __Note:__ Formerly known as "Merge expressions".

* __Motivation:__ This refactoring, in a way, behaves as the inverse of [Temporary variable elimination](#temporary-variable-elimination). When programming, we may sometimes come across unavoidably large and hard-to-understand expressions. With this refactoring, we can break down those expressions into smaller parts and assign them to local variables with meaningful names, thus facilitating the overall understanding of the code. In addition, this refactoring can help eliminate [Duplicated Code][Duplicated Code], as the variables extracted from the expressions can be reused in various parts of the codebase, avoiding the need for repetition of long expressions.

* __Examples:__ The following code provides an example of this refactoring. Prior to the refactoring, we have a module ``Bhaskara`` composed of the function ``solve/3``, responsible for finding the roots of a quadratic equation. This function returns a tuple with the roots or their non-existence.

```elixir
# Before refactoring:

defmodule Bhaskara do

def solve(a, b, c) do
if b*b - 4*a*c < 0 do
{:error, "No real roots"}
else
x1 = (-b + (b*b - 4*a*c) ** 0.5) / (2*a)
x2 = (-b - (b*b - 4*a*c) ** 0.5) / (2*a)
{:ok, {x1, x2}}
end
end

end

#...Use examples...
iex(1)> Bhaskara.solve(1, 3, -4)
{:ok, {1.0, -4.0}}

iex(2)> Bhaskara.solve(1, 2, 1)
{:ok, {-1.0, -1.0}}

iex(3)> Bhaskara.solve(1, 2, 3)
{:error, "No real roots"}
```

Note that in this function, besides the expression ``b*b - 4*a*c`` being repeated several times, including within a larger expression, the lack of meaning for ``b*b - 4*a*c`` can make the code less readable. We can solve this by extracting a new variable ``delta``, assigning ``b*b - 4*a*c`` to this new variable, and replacing all instances of this expression with the use of the ``delta`` variable.

```elixir
# After refactoring:

defmodule Bhaskara do

def solve(a, b, c) do
delta = (b*b - 4*a*c) #<- extracted variable!

if delta < 0 do
{:error, "No real roots"}
else
x1 = (-b + delta ** 0.5) / (2*a)
x2 = (-b - delta ** 0.5) / (2*a)
{:ok, {x1, x2}}
end
end

end

#...Use examples...
iex(1)> Bhaskara.solve(1, 3, -4)
{:ok, {1.0, -4.0}}

iex(2)> Bhaskara.solve(1, 2, 1)
{:ok, {-1.0, -1.0}}

iex(3)> Bhaskara.solve(1, 2, 3)
{:error, "No real roots"}
```

* __Side-conditions:__
* The name of the new variable created in this refactoring (*e.g.*, `delta`) must not conflict with the name of any other variable already defined in the same scope;

* The expression to be extracted into a variable must originally be contained within the body of a function and not be part of a guard expression;

* The expression cannot be replaced by a variable if any of its sub-expressions are not pure, meaning they have side effects.

These side conditions are based on definitions provided by members of the RefactorErl project, as described in the following link: [[1]](http://pnyf.inf.elte.hu/trac/refactorerl/wiki/RefactoringSteps)

__Recalling previous refactorings:__ Although the refactored code shown above has made the code more readable, it still has opportunities for applying other refactorings previously documented in this catalog. Note that for the calculation of the roots, we have two lines of code that are practically identical. In addition, we have two temporary variables (``x1`` and ``x2``) that have only the purpose of storing results that will be returned by the function. If we take this refactored version of the code after applying [Extract expressions](#extract-expressions) and apply a composite refactoring with the sequence of [Extract function](#extract-function) -> [Generalise a function definition](#generalise-a-function-definition) -> [Fold against a function definition](#folding-against-a-function-definition) -> [Temporary variable elimination](#temporary-variable-elimination), we can arrive at the following version of the code:

```elixir
# After a composite refactoring:

defmodule Bhaskara do

defp root(a, b, delta, operation) do
operation.(-b, delta ** 0.5) / (2*a)
end

def solve(a, b, c) do
delta = (b*b - 4*a*c)

if delta < 0 do
{:error, "No real roots"}
else
{:ok, {root(a,b,delta,&Kernel.+/2), root(a,b,delta,&Kernel.-/2)}}
end
end

end

#...Use examples...
iex(1)> Bhaskara.solve(1, 3, -4)
{:ok, {1.0, -4.0}}

iex(2)> Bhaskara.solve(1, 2, 1)
{:ok, {-1.0, -1.0}}

iex(3)> Bhaskara.solve(1, 2, 3)
{:error, "No real roots"}
```

[▲ back to Index](#table-of-contents)
___

### Splitting a large module

* __Category:__ Traditional Refactorings.

* __Motivation:__ This refactoring can be used as a solution for removing the code smell [Large Module][Large Module], also known as Large Class in object-oriented languages. When a module in Elixir code does the work of two or more, it becomes large, poorly cohesive, and difficult to maintain. In these cases, we should split this module into several new ones, moving to each new module only the attributes and functions with purposes related to their respective goals.

* __Examples:__ The code example below demonstrates the application of this refactoring technique. In this case, the ``ShoppingCart`` module is excessively large and lacks cohesion, as it combines functions related to at least four distinct and unrelated business rules.

```elixir
# Before refactoring:

defmodule ShoppingCart do
# Rule 1
def calculate_total(items, subscription) do
# ...
end

# Rule 1
def calculate_shipping(zip_code, %{id: 3}), do: 0.0
def calculate_shipping(zip_code, %{id: 4}), do: 0.0
def calculate_shipping(zip_code, _), do
10.0 * Location.calculate(zip_code)
end

# Rule 2
def apply_discount(total, %{id: 3}), do: total * 0.9
def apply_discount(total, %{id: 4}), do: total * 0.9
def apply_discount(total, _), do: total

# Rule 3
def send_message_subscription(%{id: 3}, _), do: nil
def send_message_subscription(%{id: 4}, _), do: nil
def send_message_subscription(subscription, user), do: # something

# Rule 4
def report(user, order) do
# ...
end
end
```

Applying this refactoring three times, ``ShoppingCart`` can be splitted, and some of its functions could be moved to other new modules (``Item``, ``Subscription``, and ``Util``), thus increasing the codebase overall cohesion.

```elixir
# After refactoring:

defmodule ShoppingCart do
# Rule 1
def calculate_total(items, subscription) do
# ...
end

# Rule 1
def calculate_shipping(zip_code, %{id: 3}), do: 0.0
def calculate_shipping(zip_code, %{id: 4}), do: 0.0
def calculate_shipping(zip_code, _), do
10.0 * Location.calculate(zip_code)
end
end
```

```elixir
# After refactoring:

defmodule Item do
# Rule 2
def apply_discount(total, %{id: 3}), do: total * 0.9
def apply_discount(total, %{id: 4}), do: total * 0.9
def apply_discount(total, _), do: total
end
```

```elixir
# After refactoring:

defmodule Subscription do
# Rule 3
def send_message_subscription(%{id: 3}, _), do: nil
def send_message_subscription(%{id: 4}, _), do: nil
def send_message_subscription(subscription, user), do: # something
end
```

```elixir
# After refactoring:

defmodule Util do
# Rule 4
def report(user, order) do
# ...
end
end
```

Each application of this refactoring involves creating a new module, selecting the set of definitions that should be moved to that new module, and applying the [Moving a definition](#moving-a-definition) refactoring to each of those selected definitions. Any reference and dependency issues inherent in moving functions between modules are compensated for by the [Moving a definition](#moving-a-definition) refactoring. Although this does not happen in the above example, in some cases, after splitting an original module into several smaller and more cohesive modules, the name of the original module can no longer makes sense, providing an opportunity to also apply the [Rename an identifier](#rename-an-identifier) refactoring.

[▲ back to Index](#table-of-contents)
___

### Remove nested conditional statements in function calls

* __Category:__ Traditional Refactoring.

* __Note:__ Formerly known as "Simplifying nested conditional statements".

* __Motivation:__ Sometimes nested conditional statements can unnecessarily decrease the readability of the code. This refactoring aims to simplify the code by eliminating unnecessary nested conditional statements.

* __Examples:__ The following code shows an example of this refactoring. Before the refactoring, we have the functions ``convert/2`` and ``qux/3``. The private function ``convert/2`` takes a ``list`` and a boolean value ``switch`` as parameters. If ``switch`` is true, the ```list``` is converted to a tuple; otherwise, the ``list`` is not modified. The public function ``qux/3`` takes a ``list``, a ``value``, and an ``index`` as parameters and then calls the ``convert/2`` function. If the ``list`` contains the ``value`` at the ``index``, ``qux/3`` calls the ``convert/2`` function with the second parameter set to true; otherwise, the second parameter is set to false.

```elixir
# Before refactoring:

defmodule Foo do
defp convert(list, switch) do
case switch do
true -> {:tuple, List.to_tuple(list)}
_ -> {:list, list}
end
end

def qux(list, value, index) do
case convert(list, case Enum.at(list, index) do
^value -> true
_ -> false
end) do
{:tuple, _} -> "Something..."
{:list, _} -> "Something else..."
end
end
end

#...Use examples...
iex(1)> Foo.qux([1,7,3,8], 7, 0)
"Something else..."

iex(2)> Foo.qux([1,7,3,8], 7, 1)
"Something..."
```

Note that the function ``qux/3`` uses two nested ``case`` statements to perform its operations, with the innermost ``case`` statement responsible for setting the boolean value of the second parameter in the call to ``convert/2``. As shown in the following code, we can simplify this code by replacing the innermost ``case`` statement with a strict equality comparison (``===``).

```elixir
# After refactoring:

defmodule Foo do
...

def qux(list, value, index) do
case convert(list, Enum.at(list, index) === value) do
{:tuple, _} -> "Something..."
{:list, _} -> "Something else..."
end
end

end

#...Use examples...
iex(1)> Foo.qux([1,7,3,8], 7, 0)
"Something else..."

iex(2)> Foo.qux([1,7,3,8], 7, 1)
"Something..."
```

[▲ back to Index](#table-of-contents)
___

### Move file

* __Category:__ Traditional Refactoring.

* __Motivation:__ Move a project file between directories, which contains code such as modules, macros, structs, etc. This refactoring can improve the organization of an Elixir project, grouping related files in the same d