8 ms·
Modern Functional Programming: The Onion Architecture
- gravypod 10y agoI'd not say this is a feature of functional programming. This is a feature of Object Oriented elements being included in fp languages. These are the same things we were going to happen when using Java and C++ years ago. You can even see similar graphics here: https://docs.oracle.com/javase/tutorial/java/concepts/object.html https://docs.oracle.com/javase/tutorial/java/concepts/object... I remember there was another in this tutorial that shared more with the image in this post. Although this is the same idea. You're just hiding Objects in Objects.
- wtetzner 10y agoWell, he says this pretty early on: > The onion architecture can be implemented in object-oriented programming or in functional programming.
- lmm 10y agoThe difference is that a "layer interpreter" in functional style is just a pure function that transforms values to values, so it's very easy to test in a very direct way. And we have laws that guarantee that composition works correctly (i.e. the interpretation of a composition is the composition of the interpretations). Whereas it's a lot fiddlier to confirm that an object that uses other objects behaves correctly (you have to mock the inner objects), and virtually impossible to determine whether composition behaves correctly since the object's internal state is opaque.
- mickronome 10y agoThank you for writing 'functional style' and not 'functional language'. While the latter is usually, and quite naturally, better at expressing the former, there is usually a lot to gain simply by adapting the style to the issue at hand, which not _necessarily_ implies changing languages. What follows is not necessarily of high value, I'm simply a working programmer since 20 odd years that's bit weary and sad that the craft appears to be stuck in a rut by getting stuck between an unnecessarily theory-less reality and a nirvana of unrealistic purity. It's - maybe - a backdrop to explain why I felt a need to thank you for your choice of words with so many words. If we consider every problem has a shape (loose analogue for the set of constraints thet uniquely identifies a problem) , then for every shape, or class of shapes a problem embodies, there exists an in some sense - ideal - language to solve that problem. Few are however the times when you only need to solve one discrete class of problem in the same system, but in case of mismatc between language and shape, it's quite common the only solution brought forth is to change languages. Unfortunately that solution is rarely feasible for a multitude of reasons. In the fallout after having to keep working with the same non-ideal language, the entire idea that there are multiple ways - styles - to express a solution is sadly often lost. This would not necessarily happen if the idea that style matters enough that when we can't change language, we could, and would still change how we express the solution within our constraintd. Be it in any language or paradigm under the sun, we need the words from them all to be able to talk about our problems, as they are either unique or already solved.
- lmm 10y agoThe functional mindset views programming languages almost as families or toolkits: solutions should be written in the language of the domain, and successively interpreted to the language of the machine. Thus you don't change language to adapt to a different domain; rather you write a new domain sublanguage. The challenge is if anything to avoid going too far in the other direction; lisp in particular is notorious for being so flexible that no two people's lisp styles end up compatible. I think there's a happy medium to be found. As my programming career has progressed I've become more and more in favour of Scala for everything - I think it gets pretty close to striking the right balance between the flexibility to express any given domain and the consistency to allow programmers to collaborate.
- barrkel 10y agoThe architectural pattern of implementing a program in a language close to the domain and iteratively transforming it into something that can be consumed in an execution environment long predates OO, and is in fact the principle behind compilers. It came out in a different guise under Model Driven Architecture and executable specifications a few years back. It'll pop up again in the future under some other name. The principle is as old as computing itself, though.
- eternalban 10y ago> At the center of the application, semantics are encoded using the language of the domain model. Say pg/psql. > Beginning at the center, each layer is translated into one or more languages with lower-level semantics. ORM mapping into Java? > At the outermost layer of the application, the final language is that of the application’s environment — for example, the programming language’s standard library or foreign function interface, or possibly even machine instructions. Or maybe even html+javascript. Congratulations, you have (re-)invented the layered architecture.
- ubertaco 10y ago>> At the center of the application, semantics are encoded using the language of the domain model. > Say pg/psql. Minor nitpick: "pg/psql" is not the language of the domain model. The language of the domain model is stuff like "A car is considered 'All-Wheel Drive' if the drivetrain delivers power to any/all of the axles, not just a single axle." pg/psql requires translating that domain-model language into something (roughly) like set @awdCars := (select * from cars where drivetrainAxles >= allAxles)
- lmm 10y agoOnly if you can express your domain well in SQL. For most domains you can't, you need a... domain specific language.
- asciihacker 10y ago> Beginning at the center, each layer is translated into one or more languages with lower-level semantics. ORM mapping into Java? An ORM would not have lower-level semantics would it?
- munro 10y agoThe graphics are both indeed circular which makes them look alike, but the meaning is completely different. In the OO graphic, it's representing a single cell organism, hence the circle. This is not the complete application. It's encapsulating the state of a single process, and only through externally interacting with the organism can the state be inspected & changed, all based on time. The circles in the FP represent domain logic, the inner most circle represents your high level business logic. This is the complete application. Then translating your logic to the next lower level domain, until the physical hardware layer is reached and your program becomes something concrete and runnable. This layering resembles an onion, which is also a circle.
- gravypod 10y agoThem being circular has nothing to do with what are they representing. They are showing off the idea of hiding implementation through abstracting it. This is the exact same concept that both of these photos are showing.
- munro 10y ago> Them being circular has nothing to do with what are they representing. Please read my comment, that's what it says right after the first comma. > They are showing off the idea of hiding implementation through abstracting it. This is the exact same concept that both of these photos are showing. My comment breaks down how the hiding of implementation is completely different between the two, can you point what you think is incorrect so we're not talking past each other? Or is there anything you need clarification on?
- deleted 10y ago[deleted]
- nickpsecurity 10y agoIt started in CompSci sort of in parallel with Bob Barton's B5000 designed for ALGOL, the work of Dijkstra, McCarthy's LISP, Hamilton's USL, and so on. They each came up with abstract ways to specify or implement programs for greater correctness, readability, safety, and composition. Using provers, compilers, or manual work, these would be converted into specific code at lower levels or final, machine level in ways intended to preserve high-level properties. Dijkstra went furthest in THE where the did hierarchical layers that were loop free. In parallel, there was a group trying to figure out how to compile Monte Carlo simulations on their computers in a way that was easy to specify. Their Simula was first, OOP language. SimScript, a RAND language, was a discrete, event simulation tool that came out with many similarities to emerging Simula and OOP. The main programmer had already been exposed to ALGOL, loved the heck out of it, and took some inspiration from SimScript. Hierarchical layering, careful interfaces, dynamic programming, functional composition, refinement, event-based simulation... all showing up before Simula was published in 1967. So, it anywhere from depended on to came after many things with properties key to OOP's effectiveness. It certainly got a powerful technique for structuring programs started but didn't happen in isolation or even necessarily ahead in many ways. It surprised me that needs of Monte Carlo apps is what led to OOP but not that ALGOL60 was involved. http://phobos.ramapo.edu/~ldant/oop/simula_history.pdf http://phobos.ramapo.edu/~ldant/oop/simula_history.pdf https://www.rand.org/content/dam/rand/pubs/research_memoranda/2009/RM3310.pdf https://www.rand.org/content/dam/rand/pubs/research_memorand...
- gclaramunt 10y agoAs far I understand, the difference is that in OO you normally transform data as you jump from layer to layer, here what do you have assembled is a simple program that will be interpreted by the lower layer
- slashdotdash 10y agoGary Bernhardt describes a similar architecture using a "Functional Core, Imperative Shell" in his Boundaries talk[1]. "Purely functional code makes some things easier to understand: because values don't change, you can call functions and know that only their return value matters—they don't change anything outside themselves. But this makes many real-world applications difficult: how do you write to a database, or to the screen?" "This design has many nice side effects. For example, testing the functional pieces is very easy, and it often naturally allows isolated testing with no test doubles. It also leads to an imperative shell with few conditionals, making reasoning about the program's state over time much easier." [1] https://www.destroyallsoftware.com/talks/boundaries https://www.destroyallsoftware.com/talks/boundaries [2] https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell https://www.destroyallsoftware.com/screencasts/catalog/funct...
- asciihacker 10y agoI'm enjoying watching the boundaries talk, especially when he converts the serial code the concurrent code using actors.
- VeejayRampay 10y agoI'd like to use the occasion that I'm really waiting for the video of his talk "Ideology" given at StrangeLoop 2015.
- RodericDay 10y agoSame, but for whatever he talked about in PyCon 2015
- _mhr_ 10y agoIf it helps at all, here's a transcript of that talk: https://github.com/strangeloop/StrangeLoop2015/blob/master/transcripts/Gary%20Bernhardt%20StrangeLoop%209-25-15.txt https://github.com/strangeloop/StrangeLoop2015/blob/master/t...
- junke 10y agoAt the lowest levels, the pattern can be reversed: you provide a nice functional shell around a little bit of imperative core (e.g. implementing "map" with a loop).
- bad_user 10y ago> Free monads permit unlimited introspection and transformation of the structure of your program; Free monads allow minimal specification of each semantic layer, since performance can be optimized via analysis and transformation. That is not true and this overselling of the Free monad is hurting the concept. The Free monad is nothing more than the flatMap/bind operation, specified as a data-structure, much like how a binary-search tree describes binary search. And this means an imposed ordering of operations and loss of information due to computations being suspended by means of functions. You see, if the statement I'm disagreeing with would be true, then you'd be able to build something like .NET LINQ on top of Free. But you can't.
- rtpg 10y agoMaybe this is a bit trite, but isn't the ordering given in Free simply the order of the code? At what stage does loss of information happen.
- mbrock 10y agoYeah, the free monad structures involve lots of lambdas. It's not so much that information is "lost", more that you cannot see beyond the next lambda abstraction. From a DSL perspective, it's like you can only inspect the program so far as to know the next statement in the "do" block. To see what the next statement will be, you need to actually evaluate the current one. Instead of free monads, if you want very analyzable structures, look at free applicative functors. "Applicative functors are a generalisation of monads. Both allow the expression of effectful computations into an otherwise pure language, like Haskell. Applicative functors are to be preferred to monads when the structure of a computation is fixed a priori. That makes it possible to perform certain kinds of static analysis on applicative values. We define a notion of free applicative functor, prove that it satisfies the appropriate laws, and that the construction is left adjoint to a suitable forgetful functor. We show how free applicative functors can be used to implement embedded DSLs which can be statically analysed." http://arxiv.org/abs/1403.0749 http://arxiv.org/abs/1403.0749
- lmm 10y ago
- tucaz 10y agoUnrelated to functional programming there is Onion Architecture defined by Jeffrey Palermo in 2008 which I find a very nice and simple way to architect/organize a LoB application. http://jeffreypalermo.com/blog/the-onion-architecture-part-1/ http://jeffreypalermo.com/blog/the-onion-architecture-part-1... http://jeffreypalermo.com/blog/the-onion-architecture-part-2/ http://jeffreypalermo.com/blog/the-onion-architecture-part-2... http://jeffreypalermo.com/blog/the-onion-architecture-part-3/ http://jeffreypalermo.com/blog/the-onion-architecture-part-3... http://jeffreypalermo.com/blog/onion-architecture-part-4-after-four-years/ http://jeffreypalermo.com/blog/onion-architecture-part-4-aft...
- jackmott 10y agoI didn't understand a word, and I bet 99% of people who clicked the link didn't either.
- carapace 10y agoAnd there's the rub. I don't doubt this stuff is useful, and I'd like to know more. But it seems really hard to bring this stuff "down from the mountain" in a way that makes it easier to understand and utilize for us mere mortals.
- koloron 10y agoHere are two blog posts on free monads that should be accessible for people who understand what a monad is and are able to read Haskell: http://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.html http://www.haskellforall.com/2012/06/you-could-have-invented... http://www.haskellforall.com/2012/07/purify-code-using-free-monads.html http://www.haskellforall.com/2012/07/purify-code-using-free-...
- munro 10y agoHow does this architecture constrast with Rust? Has anyone built anything like this in Rust? It makes me think of an article where the author tries to abstract the implementation of IO from the the domain logic. [1] [1] https://blog.skcript.com/asynchronous-io-in-rust-36b623e7b965 https://blog.skcript.com/asynchronous-io-in-rust-36b623e7b96...