class: middle # ?VC ## **M**ind your own business ## **V**iew ## **C**ontroller --- class: middle ## **Hi** ### *name -* Peter Saxton ### *@internets -* CrowdHailer --- class: middle ![](curl.png) ### paywithcurl.com --- class: middle ![](./explain-mvc-title.png) --- class: center, middle ![](./explain-mvc-conversation.png) --- class: center, middle ![](./explain-mvc-diff.png) --- class: center, middle ![](https://media.giphy.com/media/3o85xwxr06YNoFdSbm/giphy.gif) --- class: middle > Phoenix is a web development framework written in Elixir which implements the server-side Model View Controller (MVC) pattern. Many of its components and concepts will seem familiar to those of us with experience in other web frameworks **like Ruby on Rails or Python's Django.** --- class: center, middle ![](./getting-started-rails.png) --- class: center, middle ![](./martin-fowler-mvc.png) https://martinfowler.com/eaaDev/uiArchs.html --- class: middle ## A *little* later > MVC assumes we are manipulating regular **Smalltalk** objects. --- class: middle ![](facepalms.jpg) --- class: middle ## What is **good** software - Communicates purpose - Supports evolving requirements - Can be validated (Predictable/Testable) --- class: middle # Strategy > Tactics *“Strategy without tactics is the slowest route to victory. Tactics without strategy is the noise before defeat."* --- class: middle, center ![](./DDD-books.jpg) --- class: middle # Domain Driven Design ### Discover design don't choose it. --- class: middle ## **Domain** - A coherent subset of the universe. --- class: middle ## **Model** - A useful representation of a domain. --- class: middle ## **Ubiquitous language** - Terms used to describe concepts in the domain, and model. --- class: middle ## **Context** - The setting in which a ubiquitous language applies. --- class: middle # Tactics --- class: middle ## **Value object** - Any object whose identity is characterized by its attributes. - They should be treated as immutable --- class: middle ```elixir address = {"create", "duck", "chip"} ``` ![](w3w-london.png) *https://w3w.co/create.duck.chip* --- class: middle ## **Entity** - Concept that is defined by it's identity - Their state can evolve over time --- class: middle ```elixir order = %{ id: 1, status: :dispatched, address: {"create", "duck", "chip"} } ``` ![](squashed-parcel.jpg) --- class: middle ## **Ports** ```elixir defmodule NotificationService do @callback alert(User.t(), String.t()) :: {:ok, integer} | {:error, term} end ``` ## and **Adapters** ```elixir defmodule NotificationService.SMS do @behaviour NotificationService @impl NotificationService def alert(user, message) do # Send some SMS's end end ``` --- class: middle # Putting it all together --- class: middle ![](hexagonal-architecture.png) --- class: middle ### **Hexagonal** architecture http://alistair.cockburn.us/Hexagonal+architecture ### **Clean** architecture https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html ### **Onion** architecture https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/ --- class: middle ## **MVC** framework ``` lib/ ├── models/ ├── views/ ├── controllers/ ``` --- class: middle ## **MVC** framework 1. Realisation that last project was REST endpoints to update a database. -- 2. Hope that the next one will be the same. -- **NOTE:** it often is --- class: middle ```eex <%= form_for @changeset, user_path(@conn, :create), fn f -> %>
Name: <%= text_input f, :name %>
Age: <%= select f, :age, 18..100 %>
<%= submit "Submit" %> <% end %> ``` *https://hexdocs.pm/phoenix_html/Phoenix.HTML.Form.html* --- class: middle ![](hexagonal-architecture.png) --- class: middle # DDD lessons --- class: middle ## All models are **wrong** > Since all models are wrong the scientist cannot obtain a "correct" one by excessive elaboration. On the contrary following William of Occam he should seek an economical description of natural phenomena. Just as the ability to devise simple but evocative models is the signature of the great scientist so overelaboration and overparameterization is often the mark of mediocrity. --- class: middle ## Isolate the **model** - Use ports to obscure infrastructure details - Start from lib - Delay descisions about which exciting NoSQL DB is best --- class: middle ## Functional cohesion > Functional cohesion is when parts (of a module) are grouped because they all contribute to a single well-defined task [https://en.wikipedia.org/wiki/Cohesion_(computer_science)](https://en.wikipedia.org/wiki/Cohesion_(computer_science)) --- class: middle ## Tests are **just** one adapter By having well defined ports into the domain clear testing points are available. --- class: middle ## Know your **limits** Understand the bounds of your context --- class: middle ![](ballast-test.jpg) --- class: middle ![](flight-attendant.jpg) --- class: middle # **?VC** ~~framework~~ - Promote integrity of the model - Don't call us, we'll call you --- class: middle # Raxx ### A Toolkit for web development --- class: middle ### Web only ```elixir defmodule MyApp.WWW.Login do use Raxx.Server def handle_request(%{method: :POST, body: body}, %{greeting: greeting}) do %{username: username, password: password} = URI.decode_query if MyApp.authenticate?(username, password) do response(:ok) |> set_body(greeting) else response(:forbidden) |> set_body("Invalid login details") end end end ``` *lib/my_app/www/login.ex* --- class: middle ### Functional Cohesion ``` my_app/ ├── www/ ├── login.ex/ ├── login.html.eex/ ``` ```elixir defmodule MyApp.Login do use Raxx.Server # Part of Raxx.Kit use MyApp.HTMLView, path: "./login.html.eex" def handle_request(%{method: :GET}, _state) do response(:ok) |> render(%{}) end def handle_request(%{method: :POST, body: body}, _state) do # ... end ``` --- class: middle ### Start on demand ```elixir defmodule MyApp.WWW do use Ace.HTTP.Service, cleartext: true end ``` *lib/my_app/www.ex* ```elixir children = [ {MyApp.WWW, [%{greeting: "Hello"}, [port: 80]]} {MyApp.Admin, [%{}, [port: 4000]]} ] ``` *lib/my_app/application.ex* ```elixir setup do {:ok, service} = MyApp.WWW.start_link(TEST, port: 0) # etc end ``` *test/my_app/www_test.ex* --- class: middle # Questions? *@CrowdHailer*