From 7799d5f43f2fcaa71dceda29b7c7f5a3a8fa2629 Mon Sep 17 00:00:00 2001 From: "Yann Esposito (Yogsototh)" Date: Sun, 26 Sep 2021 15:46:20 +0200 Subject: [PATCH] First draft --- .../index.org | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/posts/0021-elegant-functional-programming-application-architecture/index.org diff --git a/src/posts/0021-elegant-functional-programming-application-architecture/index.org b/src/posts/0021-elegant-functional-programming-application-architecture/index.org new file mode 100644 index 0000000..b5a64f4 --- /dev/null +++ b/src/posts/0021-elegant-functional-programming-application-architecture/index.org @@ -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