First draft

This commit is contained in:
Yann Esposito (Yogsototh) 2021-09-26 15:46:20 +02:00
parent 1c9352bb2b
commit 7799d5f43f
Signed by untrusted user who does not match committer: yogsototh
GPG Key ID: 7B19A4C650D59646
1 changed files with 118 additions and 0 deletions

View File

@ -0,0 +1,118 @@
#+title: Elegant Functional Programming Application Architecture
#+description: An elegant and working code architecture
#+keywords: blog static
#+author: Yann Esposito
#+email: yann@esposito.host
#+date: [2021-09-26 Sun]
#+lang: en
#+options: auto-id:t
#+startup: showeverything
In this article I will expose you about how to architect your application
using function programming paradigm.
It is not tied to any programming language.
The principles in this article could probably be used by most programming
languages.
* Pre
:PROPERTIES:
:CUSTOM_ID: pre
:END:
First note that many /functional programming languages/ are not functional.
They all provide holes in order to trick the system to be faster.
Also for internal use, some advanced feature might be provided.
1. Type-classes ; this is not something I consider belongs to functional programming.
2. Clojure Protocols, ~defmulti~ ; are not something I would consider belongs
to functional programming.
And many other languages features.
Let be radical functional programmer.
Radical, means going back to the roots.
So here we go.
Functional programming is about manipulating functions with the meaning of
*mathematical functions* not what most programming language call functions.
A "function" in C, Clojure, Python, Java, Javascript is *not* a function in
the functional programming sense.
OTOH in Haskell it is /often/ a real function, but not always.
So a mathematical function is something that takes a bunch of parameters
and return a value (or not, we should allow partial functions unfortunately).
And if you provide the same parameter twice the result will always be the same.
Also, it should not have any side effect, for example, it should log, emit
sounds, ... nothing.
Whoa whoa... Give me a minute here. Why would we want to ... do nothing at
all?
Isn't writing an application about doing things?
Yes, it is.
Let just say, that, you generally, don't need more than plunging a
pure function graph into a context where an interpreter will be able to use
and this big pile of pure functions will be used to have side effect.
A big ball of pure functions are reproducible, easy to test, easy to
analyze and reason about.
Easy to expose business logic out of technical detail to access data,
etc...
So I will provide a system as radical, and simple as possible that will
have a lot of good properties that advanced functional programming methods
(like Monad, Monads transformers, Free Monads, Effect systems) are trying
to achieve.
* The Architecture
:PROPERTIES:
:CUSTOM_ID: the-architecture
:END:
The main architecture is based on the /Service/ paradigm.
A service will be a sub-application living at runtime, it will depends on
other services, and have an internal state.
So in the end your application should look like an acyclic graph of services.
Every service has an init phase, then a living phase, then a stop phase.
Every service declare a set of methods to be used and every service will
keep an internal implicit state.
Even if this look a lot like Object oriented programming.
It is in fact a quite radical functional programming architecture.
#+begin_src clojure
(def Interface
(function-1 [arg-1 arg-2] "a function"))
;; Main implementation of /my-service/
(defservice my-service
Interface
[sub-service-1
sub-service-2
,,,
sub-service-n]
(init [initial-ctx]
(let [service-state
(core/init {:sub-service-1 sub-service-1 ,,,})]
(into initial-ctx service-state)))
(function-1 [ctx arg-1 arg-2]
(core/function-1 ctx arg-1 arg-2)))
;; A test implementation of /my-service/
(defservice my-test-service
Interface
[sub-service-1
sub-service-2
,,,
sub-service-n]
(init [initial-ctx]
(let [service-state
(test/init {:sub-service-1 sub-service-1 ,,,})]
(into initial-ctx service-state)))
(function-1 [ctx arg-1 arg-2]
(test/function-1 ctx arg-1 arg-2)))
#+end_src