Fl4m3Ph03n1x
Background
For the longest time now I have been playing with the idea of doing an application that follows the hexagonal architecture:
After reading several books on the matter, this looks like something that everyone should do. It is hard for me to find a compelling reason to not use it given that you are writing any code with a decent amount of complexity (don’t use it for an Hello World app, obviously).
However, ironically, I have never found, in all my life as a programmer, any project using it. In fact, none of my colleagues I have (or ever had) even knew about it.
What now?
So, now I have decided with my free time, to create a pet project where I can implement this architecture.
This project should be simple: It is a command line app, that makes HTTP requests to an external website.
There is no database, authentication, no nothing. Just invoking the app:
# makes a hello world search in google and IO.puts the result
./my_app --greet="hello world"
So, out of the box, I know I need an adapter for an HTTP client (lets say, HTTPoison) and a JSON decoder (lets say Jason) because I want my app to be able to change between decoders.
Questions
And this is where I freeze. There is so much stuff in my head, I can’t even start.
How should I implement the port? Via an interface (module with callbacks) like Jose Valim in hix Mox article?
What should that interface be like? Have GET and POST methods or have a “greet” method?
What about my adapters?
It really feels like that although I have read extensively about the topic, I am incapable of processing the information into something useful.
A code sample would really help.
Has any of you ever did something similar to this in Elixir?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
al2o3cr
Very much the latter -
GETandPOSTare concepts of the outside world, not the core (unless you’re modeling an HTTP proxy or something).One of the greatest challenges with an approach like this is distinguishing exactly which side of that boundary things live on, especially early on when there’s exactly one implementation of each interface.
Destroy All Software has a popular writeup “Functional Core, Imperative Shell” that talks through a lot of similar tradeoffs:
Fl4m3Ph03n1x
I am very familiar with his talks:
This is a very interesting discussion (IMO), you may want to check it
LostKobrakai
I feel like this might actually make it harder than easier, because there’s hardly any business logic to speak of. There’s “CLI App” – which is the bad outside world – and “http requests” – which is the bad outside world – and nothing in between worth noting by the description you gave.
Try answering the question what your app does on it’s own without the outside world.
For a different example: a calculator. There’s the input of the calculation to be done (maybe string based), then the business logic of parsing the input into an AST of calcuations to be done and then the application of the calculations, which give you the result. This internal result is then converted back to a CLI based visualisation.
For something like this the boundaries are much more clear. The functional core is the parsing to ast, and the calculation itself, while the imperative shell is the CLI stuff of retrieving argv and turning the result into something you can print to the CLI (stdout), possibly adding CLI specific coloring tags and such.
Fl4m3Ph03n1x
Nothing. Does this mean my app can’t follow the hexagonal and functional architectures?
I guess I could read some translations from a file and make a request for 3 greeting languages, but then again I would just be reading from a file and doing nothing else.
This is rather confusing … everything…
LostKobrakai
You still can, but the inner part will be empty. The whole app will be interacting with the outside world on either end and just some glue code in between. Your app basically doesn’t have a core, as it’s doing nothing with the data it handles of external resources.
Fl4m3Ph03n1x
Do you happen to know where I can find a good example of an app in Elixir that uses this architecture?
Anything really goes at this point.
nthock
Last year, I am pretty obsessed with the Hexagonal architecture and trying to implement it in Phoenix. I learn that if your application has a portion where there are some logic to it (i.e. not CRUD related), then hexagonal architecture makes sense.
For example, think of a Todo application that give you analytics on how many tasks you have completed every day, and even forecast how many tasks you will complete tomorrow given the current productivity.
The code to tabulate the tasks completed everyday, and the forecasting logic for tomorrow is something that make up the core of your hexagonal architecture. It can and should be shield from your HTTP and your DB layer. Ideally, the core should also be pure. It doesn’t maintain state. It merely just takes in data, and return the output.
However, most applications will have their fair share of CRUD operations. Can we use hexagonal architecture for this? I think it is possible, and I have tried out an example by defining my own mock Repo. But after some time, I think it is not worth the effort.
LostKobrakai
This is exactly the reason why I feel the more trivial an application becomes the more difficult it’s to starting using an hexagonal architecture for it as one will constantly be thinking about all the added complexity without much tangible benefits. If all an app does is forward inputs to storage there’s no “core functionality” to speak of.
That’s why I suggested a calculator as a better example. It does actually have core functionality. This core functionality might be powered by a CLI interface, but could just as well be adapted to e.g. an http interface.
Tbh most phoenix projects use an architecture, where the http interface is already optional, as functionality is contained in contexts not in controllers. So there are lot’s of examples on that end. A good one might be nerves_hub, as it actually has both a CLI and a web based interface. There are few projects I know however, which treat their database as the bad outside world, which you’d need an interface/adapter for.
There’s a cost/benefit decision to take for keeping functionality hidden behind an interface and as most people seem to be controlling their db in their stack the benefits are not as great as e.g. for a third party api, where uncontrolled network and services are involved. For third party apis you often see them hidden behind interfaces even just to enable mocking. I found the unit testing book of manning to actually explore the space of internal vs external dependencies quite well. Most people only put dependencies behind interfaces, which they’ll also mock (Unmanaged dependencies* in the books terms), but don’t do that for things they don’t mock (Managed dependencies** in the books terms).
** out-of-process dependencies you have full control over
Fl4m3Ph03n1x
I have read that book not long ago actually
My problem with that book is that it focuses on the Detroid School of TDD, instead of the London School of TDD, which I am now trying to learn.
It is somewhat confusing to me, most people I know of seem to prefer the Detroit school of TDD even though the London one is considered a gateway to functional programming due to its different set of practices. Elixir is seen as a somewhat functional language, so it should fit the second model.
That book also mentions the hexagonal architecture and its evolution, the functional architecture, which the author claims to to be so hard to implement it might was well be impossible, something I have already discussed in this forum and found to be not as he says (the author is simply not aware of patterns to solve the issues he mentions).
But this is another discussion for another time.
You wouldn’t happen to know any examples of calculators, right? xD
LostKobrakai
From the perspective on how you implement DI/Mocks/… there’s no difference between both. The London School just mocks out / puts behind interfaces almost any depenendencies and their tests are concerned with smaller chunks of code – units in the language sense a.k.a. classes/modules and not units in the sense of set of code of a single exposed functionality.
Take what people do for third party api’s (which both schools mock) and apply the same approach to all your other dependencies (db and so on) and you should reach what the london schools suggests.