Skip to content

Instantly share code, notes, and snippets.

@CrowdHailer
Created September 30, 2015 15:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save CrowdHailer/edbbbf7440f0b85e053e to your computer and use it in GitHub Desktop.
Save CrowdHailer/edbbbf7440f0b85e053e to your computer and use it in GitHub Desktop.
Creating boundary modules for elixir applications. These have their implementation set during the configuration step. In this example we switch clock between system clock and a dummy clock
# This module represents a behaviour and when used picks from the Application configuration which implementation will be used
defmodule Clock do
@callback now() :: Integer.t
defmacro __using__([]) do
module = Application.get_env(:my_app, :Clock)
quote do
alias unquote(module), as: Clock
end
end
end
# In config/dev.ex and in config/prod.ex we set up the module that we would like to use as the implementation for the Clock boundary
use Mix.Config
config :my_app, Clock: SystemClock
# In config/test.ex we use a Dummy Clock implementation
use Mix.Config
config :my_app, Clock: DummyClock
# Returns a constant value for testing purposes.
defmodule DummyClock do
def now do
# Time at 15:42 on 30th September 2015
14436241340007622
end
end
# All production code just uses the Clock module and has no knowledge of the possible change in implementation
defmodule MyApp do
use Application
use Clock
def time do
Clock.now
end
end
# This is an implementation for the Clock boundary that asks the operating system for the current time.
defmodule SystemClock do
@behaviour Clock
def now do
round(:erlang.system_time(:nano_seconds))
end
end
@CrowdHailer
Copy link
Author

A functional program that wants to perform useful work must interact with stateful services. The simplest example I could think of was getting the current time but more likely situations would be net requests or database access.

The purpose of this code sample is to wrap these surfaces behind a single module. In tests it is very likely that you would want to not access the real services so this gives a way to provide fake implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment