Which Is More Beautiful Architecture – FP or OOP?

image Recently, upon the recommendations of a few people, I picked up a copy of the book “Beautiful Architecture: Leading Thinkers Reveal the Hidden Beauty in Software”.  This book is a great read and includes essays from some of the top minds in software today.  Some of the topics covered are:

  • How Facebook’s architecture is the basis for a data-centric application ecosystem
  • The effect of Xen’s well-designed architecture on the way operating systems evolve
  • How community processes within the KDE project help software architectures evolve from rough sketches to beautiful systems
  • How feature creep has helped GNU Emacs gain unanticipated functionality
  • The magic behind the Jikes RVM self-optimizable, self-hosting runtime
  • The design choices and building blocks that made Tandem the choice platform in high-availability environments for over two decades
  • The differences and similarities between object-oriented and functional architectural views
  • How architectures can affect the software’s evolution and the developers’ engagement

But one essay in particular caught my attention was Chapter 13 Software Architecture: Object-Oriented Versus Functional by Bertrand Meyer.  In this writing, he steps through an example application of financial contracts, as presented in both a presentation called “Composing contracts: An adventure in financial engineering” by Simon Peyton-Jones, Jean-Marc Eber and Julian Seward, along with an associated presentation by Jean-Marc Eber called “Compositional Description, Valuation, and Management of Financial Contracts:  The MLFi Language”. 

Bertrand Meyer’s overall conclusion is that given the above functional solution, an object-oriented design, especially supporting such features as closures is better than the functional approach as it can provide higher-level abstractions more supportive of extension and reuse.

Laying Out The Case

Dr. Meyer defines what architecture “beauty” is from his 1997 hallmark book, “Object-Oriented Software Construction, Second Edition” as three objective criteria:

  • Reliability
    Does the architecture help establish the correctness and robustness of the software?
  • Extendibility
    How easy is it to accommodate change?
  • Reusability
    Is the solution general, or better yet, can we turn it into a component to be plugged in directly, off-the-shelf, into a new application?

Using the above criteria and the functional examples cited, there are a few issues as noted with his essay such as the lack of data points, lack of detail, and a specific focus on modularity, whereas the functional programming examples had a focus on other criteria such as elegance of a declarative approach.  The biggest drawback to this essay is that most, if not all Object Oriented examples revolve around the use of Eiffel, which is a fringe language and not in the mainstream thought in the Object Oriented world.  To focus on this versus a mainstream functional language such as Haskell has some serious drawbacks that I don’t think can be reconciled in this essay.

Now, I’m not going to go through the example as I linked them above for you to dissect at your leisure.    Instead, we’re going to focus on the single issue of modularity between the two approaches.

Extendibility/Reusability

To speak to the reuse and extendibility issue, the functional example is heavy in the use of combinators, which are functions that take functions as arguments and return new functions.  The idea is that the financial world has a lot of jargon and instead of specifying a large set of contracts ahead of time, we could compose them using a strict set of combinators.  This way, we have the ability to define new unforeseen financial contracts with relative ease in a declarative manner.  The paper is quite compelling for how to build composable Domain Specific Languages around financial modeling, for which functional programming is widely used.

To the author the idea of defining combinators does not scale to large applications and must be divided into modules.  In turn, the extendibility problem arises on how you modularize said code while affecting the fewest modules possible.  Another issue is that with a one module approach, this does not help reusability as you wish to have only a subset of those operations imported.  Careful modularization can get around these issues and I do not necessarily see this as a stumbling block.  Instead with a good strategy on modularization and qualifying imports can solve a lot of these issues.  Also, the use of type classes can add extendibility to your architecture by defining a set of operations in which other types can

Managing State

Another issue raised by the author is state management.  The notion of stateless programming is essential to the pure functional programmer.  State and unmanaged side effects are indeed the bane of concurrency.  Instead, Haskell has the notion of monads which allow for the modeling of not only state, but exception management, as well as input/output operations.

Dr. Meyer doesn’t have a concern about the whether these concepts are hard to learn, as they shouldn’t be, but instead, if they are worth the effort at all.  Instead, through the use of Command Query Separation, where queries return results but do not alter the world, whereas commands alter the state of the world and do not return a value.  I believe, to rely on this design pattern instead of enforcement through the type system is his undoing.  Most imperative/object-oriented programmers do not follow this rule and thus should only confine his comments to Eiffel alone.  I believe once again, his focus on Eiffel is undercutting his credibility that well known OOP principles can subsume a Functional Programming example.

This analysis could go on and on, but must this be an either/or battle?

The False Battle

With the exclusion of Java, most modern languages have been evolving to include such concepts as closures, which come from the functional world.  Even the Eiffel language that has been written by the author, has incorporated “agents” which are his term for closures.  And then we have multi-paradigm languages such as F# and Scala which take more of a functional programming approach with the full support of imperative and object oriented features.

Although at this point in history, functional programming languages are less popular in mainstream development, it’s hard to now avoid their influence.  With the increased attention to concurrency and parallelism, the ideas from functional programming such as lack of state and immutability are gaining momentum as we realize the peril of shared state.  Instead of this battle, where can object oriented technologies learn from functional programming and vice versa?

How Functional Programming Influences

Let’s try another tactic with this and talk about where functional programming techniques have their biggest influence.  Brian McNamara, of the F# team, laid out the argument well in his post “How does functional programming affect the structure of your code” in which he describes its effects in three distinct areas:

  • In the Large
    Covers overall architecture and high level design.  This is where the modularization of our code has its biggest influences.  To instill laziness as a default architecture, compose message passing systems and high performance computing concerns is where functional programming can have its greatest impact.
  • In the Medium
    The medium covers more lower level API decisions that we make.  When combined with a good modularization strategy, can yield great results.  Many times as well the object oriented design patterns such as the command, builder, strategy and visitor patterns can better be expressed through functions. 
    Also, the use of discriminated unions, records and collection structures can create concise and rich domain models using pure functional structures.
  • In the Small
    By programming in the small, we mean at the actual function level.  With an immutable by default posture, we are better able to express our values without type annotations and the compiler is better able to make decisions based upon that.  Functional composition is also very much in effect at this level as we build more powerful functions from the small pieces to create rich solutions.

By understanding these concepts help us better understand where functional programming has its greatest influence and where we can use the techniques even if not in a pure functional language.

Conclusion

Overall, the arguments presented by Bertrand Meyer were persuasive in some ways, yet lacking in others.  Unable to cite more real world applications leaves me wanting.  Without this, the modularization issue cannot be addressed in full.  Other areas such as insisting on Command-Query-Separation as a default falls largely on deaf ears outside of the Eiffel community.  I do realize the more progressive teachers are starting to focus on this, but for the most part, CQS is largely untaught.  Instead having the type system express our side effects is a much more powerful option.  Overall, I thought a lot of the arguments given his bias and the lack of better examples, fell flat.  Using Eiffel, a non-mainstream OOP langauge doesn’t help his case and should have focused on more mainstream approaches as in C#, and Ruby among others.

So, who wins?  That’s a good question.  If you’re in a world resigned to side effects then OOP might just be for you.  Else, Haskell and the lessons learned from the language can be powerful instruments in creating rich and beautiful architectures using pure functional techniques.  I feel with time and maturation, the functional programming community can contribute more to the architecture picture.  The battle continues?

This entry was posted in Book Reviews, C#, F#, Functional Programming, Haskell, OOP. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • rymndhng

    Thank you for summarizing the ideas of the article. I’ve dabbled with a big of Scala, Clojure, Javascript, Ruby but now do Java for work. I relate to the struggle between choosing functional or OO approaches to my work. It’s humbling when coming from languages with much more expressive power to Java where basically none of these higher level abstractions exist — I have experimented building some of them myself (to the surprise of co-workers because the code isn’t Java like). What was fascinating about this article is how relatable this is to how I approach work. Thanks for summarizing and I will definitely check out the linked articles.

  • Bent Rasmussen

    I think it is only natural that Dr. Meyer defends OOP based on his vision and implementation of it.

    Pick your weapon of choice! To say he cannot do this is to limit your opponent just as whatever functional constructs he may have neglected can be seen as a way to weaken his opponents through false representation.

    It is an intellectually unworthy tactic.

    Arguing that what Eiffel is now, is unfair to use, is just as unfair as arguing that what FP will become is superior.

    Both sides are in my oppinion biased. Bias is fine, but it must be fair. Let both sides, based on the same criteria, express their best possible solution and *then* argue over the pros and cons of each objectively, if you’ll excuse the term.

    (Personal bias leaning towards the functional world, with strong tendencies of convergence and reconcilliation as witnessed in Scala!)

  • http://incrediblejourneysintotheknown.blogspot.com/ Daniel Earwicker

    I think this attack from Meyers can only be good news for FP – it shows that it is becoming mainstream. When C++ was the hot language, Meyers focused all his ire on it, and when Java came along he attacked Java. In both of those cases, he had many great points to make, because Eiffel really was objectively better than them in a lot of ways – but they had some largely historical or coincidental advantages that made them more popular. So now FP is coming to prominence, he’s attacking FP – but this time I’m tempted to regard it as overly defensive of his own language. Since OO came along, FP has continued evolving independently and there is a lot that it can teach the OO community/languages. So it would make a lot more sense to ask “What can OO languages profitably learn from FP?” than to set them up as opposing factions. Looking forward to reading the book so I can make up my own mind…

  • http://podwysocki.codebetter.com/ Matthew.Podwysocki

    @Raoul,

    Yes, I think we can. I was just moved to write this as a response to what seemed to be an either or approach instead of looking for the synergies within the two approaches.

    Matt

  • http://podwysocki.codebetter.com/ Matthew.Podwysocki

    @Dean Michael Berris,

    I agree that a combination of the ideas can indeed be powerful. With the isolation of mutation, immutability, first class functions and mixing in OOP can be a powerful programming model as Scala and F# have certainly attested to.

    Well, in C++0x, there is a bit of effort to get closures and other functional items in the language itself. I think it depends on how you mix the paradigms together. For example, through the use of LINQ, C# has made the leap to functional quite painless for most, without many of them knowing that they already did it. That was part of my recent talk that they were already doing a lot of those concepts.

    I think the overall conclusion is that with FP constructs mixed effectively with OOP can indeed yield powerful results. Keeping in mind of course that I’m still with my foot in the FP camp as to isolate mutation,etc.

    Matt

  • Raoul Duke

    wow. why can’t we all just get along?

    Scala, F#, O’Caml, Oz, all support the idea that sometimes you need to deal with state, and maybe you don’t want to have to grok monads to do it.

  • http://www.deanberris.com/ Dean Michael Berris

    I am a Haskell newbie but I program in C++ at a high level (even on system-level code). I haven’t read the book, but I would say the combination of functional programming with object oriented modeling is definitely powerful.

    I have to some degree been able to apply functional programming principles in the work I do with C++, but I know that it’s a stretch to use FP in an imperative language. Thinking about the problem a little more, the only way OOP will give an upper hand in FP is if you already have a good model or framework to deal with in implementing your solution. Getting to that point with OOP is too rigid to be extensible enough, and FP makes it so much simpler.

    Overall, if you can somehow combine the concepts (like how you can do it with C++) and get a good balance, it shouldn’t be a mutually exclusive situation between OOP and FP.

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @John Bender

    I agree that when we design using FP constructs, functions tend to be small and reusable by default. Then we can combine these together in interesting ways with combinators, but as well, we can extend through typeclass, functor and monad implementations as well. That, unfortunately, wasn’t covered in this essay and I wish it were.

    Matt

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @El Architect

    Heh, indeed it’s a little higher level than most posts, but speaks to a large issue that seems to be raging in terms of what composes a beautiful and extensible design.

    Matt

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Foo

    That’s another angle we could take on this with regards to OOP versus OOM. I’ll have to think about that a little bit more. Are we talking about MDA?

    And yes, you can get quite rich architectures following a pure functional model.

    Matt

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @SimleM

    I agree that functional can be easier to understand. I’ve heard feedback that many high-school age children were able to pick up Haskell much easier than those who have spent a large amount of time in imperative and object oriented coding styles.

    I’m curious though what your experiences have been with the functional side in terms of building real world apps.

    Matt

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Praki Prakash

    Absolutely, it was a foregone conclusion and I think he saw the one extendibility model as mentioned in that one piece and really exploited it. It’s not as if combinators are the only extension point. Type classes, functors and others play a role in that. Modularization does play a part and I’m not quite sure we’re there yet in that area.

    Matt

  • El Architect

    Interesting discussion, too bad that no one in the real world will ever understand what you’re on about. Now let me get back to designing my anemic domain model…

  • Foo@yahoo.com

    Have you pondered the difference between object oriented programming and then object oriented modeling?

    There is some real merit to functional implementation.

  • http://tinyurl.com/dfbu9u SimleM

    I think OOP is the best because if offers you the best data abstraction. Also, you can extend the classes as much as you want, creating the perfect system for you. For the beginners, the functinoal mode can be easier to understand.

  • Praki Prakash

    Understandably, Dr Meyer teaches OOP with a religious fervor. He also likes to point out the superiority of Eiffel over other OO languages. Given his long dedication to Eiffel language, his conclusion that OOP is better than FP has to be a foregone one, don’t you think?

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @JS

    I’m very familiar with the book thank you as I’ve read it enough times. Given those restrictions that he had, I don’t think he picked a good enough example and that’s a lot of my point. To say that combinators is “the” FP solution is what I had an issue with. We have other options as well at our disposal including monads, functors, type classes and so on. So, all in all, I think the example that he picked was suboptimal to which he acknowledges and that’s what I’m pointing out.

    Matt

  • JS

    Hello Matthew,

    Your comments here suggest that you did not understand Dr. Meyer’s article well enough to critique it. Had you understood it, you wouldn’t spend your time complaining about the use of Eiffel or writing about the virtues of stateless programming and would address the main point of the piece:

    “The functional programming approach predates object-oriented thinking, going back to the Lisp language available for almost 50 years. To those fortunate enough to have learned it early, functional programming will always remain like the memory of a first kiss: sweet, and the foretaste of even better experiences. Functional programming has made a comeback in recent years, with the introduction of new languages such as Scheme, Haskell, OCaml and F#, sophisticated type systems, and advanced language mechanisms such as monads. Functional programming even seems at times to be presented as an improvement over object-oriented techniques. The present discussion compares the two approaches, using the cited software architecture criteria. It finds that the relationship is the other way around: object-oriented architecture, particularly if enriched with recent developments such as agents in Eiffel terminology (“closures” or “delegates” in other languages), subsumes functional programming, retaining its architectural advantages while correcting its limitations.”

    Dr. Meyer then lists four qualifications to this statement:
    1) Few data points,
    2) Lack of detail,
    3) Specific focus, and
    4) Experimenter bias.

    If you disagree with the three criteria presented for architectural quality, then go ahead and show why other criteria for architecture are somehow better. If you can show that Dr. Meyer is mistaken in the claim that object-oriented designs (supplemented with closures) can subsume the functional design and yield a superior architectural design, please try and show it.

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @shapr

    Thanks for the comments. I agree and shouldn’t have been an either/or but to show how each can approach the problem. Each have their own strengths and weaknesses, hence my criticism of the essay.

    The design patterns is something I’m particularly interested in right now. I think there needs to be some sort of SOLID like principles for FP much as there is for OOP which are guiding principles on designing maintainable and well designed functional code. And you’re right that many of the GoF Design patterns simply aren’t needed in a pure FP mindset. And I think you’re right about what a design pattern is.

    Thanks for the link! Good stuff there.

    Matt

  • http://nickelcode.com John Bender

    I think FP lends itself to more stable systems as more functional languages have immutable variables, functions without side effects, and if you want to get into Monads, composability.

    The structure is harder to work with but when used properly, languages like erlang/haskell lead to very stable systems.

  • http://www.scannedinavian.com/ Shae Erisson

    I agree, there’s no need to fight, different tools for different uses.

    I once conducted a fun exercise to teach myself about the differences and similarities between FP and OOP.
    I tried to figure out how each of the Design Patterns in the original book would be implemented in Haskell.
    Most of the patterns were simple, a few were very hard, and a few were not needed. On the Haskell side there were a few new patterns (worker/wrapper) as well.

    Perhaps a design pattern describes an impedance mismatch between reality and a particular programming language?

    For something else interesting along these lines, check out FPS for OOP:

    http://c2.com/cgi/wiki?FunctionalPatternSystemForObjectOrientedDesign

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Lance and @Andrew

    Reworked the post just a little bit. Hopefully better now.

    Matt

  • Andrew

    I think you mean “tack” where you say “tact”.

  • Lance

    The book image’s float is messed up and is hiding the first paragraph or so.