AlloyCI Dev Diary — Part 2
Tags: elixir, opensource, sideprojects, devdiary
Published: 2018-03-22 23:20:58

---
title: AlloyCI Dev Diary — Part 2
published: true
description: Structuring a new Phoenix Project
tags: elixir, opensource, sideprojects, devdiary
cover_image: https://thepracticaldev.s3.amazonaws.com/i/nrgqc1fqun6fob3q7cr6.jpeg
---

# Structuring a new Phoenix Project

![Photo by valor kopeny on Unsplash](https://images.unsplash.com/photo-1440613740265-a37aa8a61131?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=78b205db80905893f41d2f694258e376&auto=format&fit=crop&w=2674&q=80)

This blog post is part of a series of posts detailing the development process of AlloyCI. The previous entries have been:

- [Part 1: Starting a new Project](https://dev.to/supernova32/alloyci-dev-diary---part-1--1ai9)

---

If you are coming from a Rails background, you might find the folder structure of a Phoenix project a bit weird, specially after the changes in 1.3. But don’t be put off by this, the structure actually makes a lot of sense, specially the new 1.3 structure.

Unlike Rails, there is no `app/` folder where most of your code will live. Phoenix 1.3 projects follow the structure of pretty much any regular Elixir project, this means that most of your code will live inside the `lib/my_app` folder.

As you might now, Phoenix 1.3 changed the way projects are structured. Before this change most of your code would be under `web/`, with little to no further organizations. You would have a models directory, where you would put all your business logic, without much consideration as to how they interact together. This folder would get pretty large, pretty fast. Also the name model seems to imply an object, but in Elixir, there are no objects, so storing your data access layer under a folder named "models" makes little contextual sense.

## Data & Contexts

Phoenix 1.3, by default, guides you towards a better way of organizing your code. Controllers, Views, Templates go under `lib/my_app_web`, database migrations and related files go under `priv/repo`, and the rest of your Elixir code will live under `lib/my_app`. This is the basic setup, and you can tweak it, and change it as much as you like. You have complete liberty as to how to organize your code.

Since I started writing AlloyCI before Phoenix 1.3 was fully released, some of the folder structure is different than the one the latest 1.3 generators create. I prefer the way AlloyCI is structured right now, because I really don’t like the way they renamed the `web/` folder to `alloy_ci_web/` and everything inside it from `AlloyCi.Web.XXX` to `AlloyCiWeb.XXX`. I really prefer the separation in the module name, and the fact that the app name is not repeated in the web folder name. Thanks to the flexibility Phoenix provides, I don’t need to follow the conventions, though.

Anyways, the most important part about the structure changes, is that Phoenix now guides you towards using contexts for structuring your data access layer.

Using AlloyCI as an example, we have the `Accounts` context (which is under `lib/alloy_ci/accounts` folder), where the `User`, `Authentication`, and `Installation` schemas live. These 3 schemas are closely related, and belong to the same business logic, namely the handling of Accounts.

If you look closely at the files under the accounts folder, you will see that there are no functions in the schema files, other than the `changeset` function. This means that I would need to either go straight through `Ecto` to manipulate the database data (not recommended) or that I need an API boundary that will let me perform actions on the accounts related schemas.

This is where the `AlloyCi.Accounts` module comes into play. This module is the boundary with which AlloyCI will interact if it needs to perform an action on any of the schemas related to an Account. All public functions of this module provide an easy way to manipulate the data, while providing security through a layer of indirection.

This is the purpose of contexts. They provide a boundary between your data layer and your business logic, and allow you to have an explicit contract that tells you how you can manipulate your data. It also allows you to stay independent from Ecto.
Let’s say, in the future, you’d like to switch from Ecto to the “latest, coolestDB driver”. If you didn’t use an abstraction layer, like the contexts, you would have to refactor every function across the codebase that used Ecto to communicate to the data layer. But since we are using contexts, we would only need to refactor the code inside the context itself.

## Data Presentation

The code that will actually present your data to the user can live under the `lib/my_app/web` or `lib/my_app_web` folders, depending on how you want to structure it (the automatic generator will default to `lib/my_app_web` but I prefer the former).

In here you will find the folders where your controllers, views, templates and channels will live. Let’s start with the presentation layer.

### Views & Templates

If you come from a Rails background, you might wonder why there are two components to presenting the data, when in Rails all you need is the views folder. In Phoenix, the “views” are not composed of templated HTML files, but rather they are regular Elixir modules. These modules are there to help you share code with the template, and fulfill a similar purpose as the Rails “View Helpers”, but are, by default, specific to a single controller (other views are not loaded, unlike Rails that loads all view helpers, regardless of the controller being called). 

This separation makes it easier to use the same signature on similar helper functions needed to present data (without really overloading them), depending on which controller is being called, thus simplifying your code.

The templates are, then, where your HTML code lives. The template files are saved as `*.html.eex` files (meaning embedded Elixir), and are very similar to `erb` files. The syntax is exactly the same, but instead of Ruby code inside, you write Elixir code 😄

A very important distinction between Phoenix and Rails is how you share information between the controller and the template. In Rails, it is enough to declare an instance variable with `@something` and it will be available to the template/view.
Given the functional nature of Elixir, in Phoenix you need to explicitly pass the information you wish to be available to the views in the render function. These are called assigns. As an example, here is the `show` action of the `PipelineController`:

```elixir
def show(conn, %{"id" => id, "project_id" => project_id}, current_user, _claims) do
  with %Pipeline{} = pipeline <- Pipelines.show_pipeline(id, project_id, current_user) do
    builds = Builds.by_stage(pipeline)
    render(conn, "show.html", builds: builds, pipeline: pipeline, current_user: current_user)
  else
    _ ->
      conn
      |> put_flash(:info, "Project not found")
      |> redirect(to: project_path(conn, :index))
  end
end
```

Everything that comes after "show.html" are the assigns, so the variables available to the templates related to the show action are `builds`, `pipeline`, and `current_user`. We can see an example of how to use them in this snippet from the pipeline info header:

```html
<div class="page-head">
  <h2 class="page-head-title">
    <%= @pipeline.project.owner %>/<%= @pipeline.project.name %>
  </h2>
  <nav aria-label="breadcrumb" role="navigation">
    <!-- Breadcrumb -->
    <ol class="breadcrumb page-head-nav">
      <li class="breadcrumb-item">
        <%= ref_icon(@pipeline.ref) %>
        <%= clean_ref(@pipeline.ref) %>
      </li>
      <li class="breadcrumb-item">
        <%= icon("github") %>
        <%= sha_link(@pipeline) %>
      </li>
      <li class="breadcrumb-item">
        <%= icon("book") %>
        <%= pretty_commit(@pipeline.commit["message"]) %>
      </li>
      <%= if @pipeline.commit["pr_commit_message"] do %>
        <li class="breadcrumb-item">
          <%= icon("code-fork") %>
          <%= @pipeline.commit["pr_commit_message"] %>
        </li>
      <% end %>
      <li class="breadcrumb-item">
        <%= icon("tasks") %>
        <%= String.capitalize(@pipeline.status) %>
        <%= status_icon(@pipeline.status) %>
      </li>
    </ol>
  </nav>
</div>
```



Once a variable has been assigned, it is available to the template via `@var_name`, just like with Rails. Functions defined in the view file of the same name as the controller (in this example `pipeline_view.ex`) are immediately available to the template. In the above example, `sha_link/1` creates an HTML link to the specific commit on GitHub.

### Controllers

In structure, Phoenix Controllers are very similar to Rails Controllers, with the main difference being described above. When generated by the helper tools, they will have the same `index`, `show`, `edit`, `update`, and `delete` actions as their Rails counterparts. And just as with Rails Controllers, you can define any action you desire by defining a function, and connecting a route to it.

### Channels

Phoenix Channels are used to communicate with the web client via Web Sockets. They are similar to ActionCable in Rails, but in my opinion, much more powerful, and performant. In AlloyCI, they are used to push the output of the build logs in real time, and to render a pre formatted piece of HTML code to show the user’s repositories (more on how AlloyCI uses Channels will be discussed in another post).

### Routes


Routes in Phoenix are defined in a somewhat similar way as Rails Routes. Some of the syntax is different, but it is immediately recognizable and feels familiar. Have a look at how the project routes are defined on AlloyCI:

```elixir
scope "/", AlloyCi.Web do
...
  resources "/projects", ProjectController do
    resources("/pipelines", PipelineController, only: [:create, :delete, :show])

    resources("/builds", BuildController, only: [:show, :create]) do
      get("/artifact", BuildController, :artifact, as: :artifact)
      post("/artifact/keep", BuildController, :keep_artifact, as: :keep_artifact)
    end

    resources("/badge/:ref", BadgeController, only: [:index])
  end
...
end
```

The real difference when it comes to routes, between Phoenix and Rails, is the power that you get when using plugs. We will discuss them in detail in a future post.

---

And there you have it. That is the basic structure of a Phoenix project. There are other components that we haven’t covered here, like Plugs, or Background Jobs. We will discuss these advanced topics in a future blog post.