Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

OOP has never been just about computing. It's strength is that it allows the business rules to be most directly mapped to the code that needs to be written. When both parts of this process are performed by the same person it loses much of it's value (until the problem gets larger and you need more than one person). As we have better computing tools in modern languages it is more often the same person. It has never been considered more efficient or easier for the programmer alone, just the whole problem solving process in general, especially in teams.


> It's strength is that it allows the business rules to be most directly mapped to the code that needs to be written.

Absolutely this. Discussions around OOP vs functional always seem to ignore this massive boon to productivity that OOP brings. Being able to create something of a DSL and map your business rules onto basic operations on this DSL is a huge win. The trick is to design your objects and operations such that the salient rules "rise to the top" of the stack, and thus can be easily programmed and verified at the highest level of abstraction.

Of course a DSL comes with its own drawbacks. Having to learn a new "language", with operations that are sometimes just renaming more basic operations has an extra cognitive load that can't be ignored. This is why there is a threshold of complexity below which you're better off just writing it straight imperative/functional style.


> Being able to create something of a DSL and map your business rules onto basic operations on this DSL is a huge win.

Hold on - how is this a concept specific to object-oriented programming? Creating a DSL for your problem domain and solving the problem in the new language is exactly what functional programmers have been doing for decades! E.g. here's a mini-DSL in Haskell for parsing CSVs, built on top of the Parsec parsing DSL:

    cellContents = many (noneOf ",\n")    -- match up to first comma/newline
    
    remainingCells = (char ',' >> cells)  -- comma => parse more cells
                 <|> (return [])          -- else done

    cells = do first <- cellContents
               rest <- remainingCells
               return (first : rest)

    eol = char '\n'                       -- match newline character

    line = do result <- cells
              eol
              return result
Building DSLs is most emphatically not something specific to OO programming.


Of course, anything you can create abstractions with you can create a DSL of sorts. But I think most would agree that OOP is the more natural paradigm for this.


If anything it's quite the opposite; most OOP languages are extremely limiting for DSL creation as compared to most FP languages.


Most would agree because most have never used anything other than OOP. That isn't saying anything interesting. I find OOP to be most often awkward and difficult to express the rules of my application in. Functional programming does it quite naturally, as it is all about creating small simple components and combining them to produce larger components. My rules are simply the combination of smaller rules applied in order.


This is exactly how I feel also.

This simple logic of fitting smaller things together to make bigger things has always delivered superior results for me regardless of the language in use.

OOP seems ass backwards to me but everyone I talk to generally doesn't have a clue how FP is different to OOP!


The difference, at least in my eyes, is that OO languages have a convention for the grammar of the DSL.


At some point--well before Java--sufficiently constrained syntax turns your DSLs into libraries, which tend to be less close in design to the given domain than actual DSLs.

Put another way: with Java or Python, you coerce your problem domain to fit the language. With Lisp and Haskell, you coerce the language to fit the problem. I personally like the latter approach, but I suspect it's also a matter of preference.


It's a matter of maintainability. For the startup scene, the latter provides faster development, more flexibility, and a more intuitive codebase.

When you reach corporate scales, convention needs to aid in the grokking of the codebase.

I greatly prefer JavaScript in a functional style when I'm coding for myself, because I know the code in and out, but I prefer something more like C# when working on a team because then at least there is a set of more strict conventions we have to adhere to.


I think which one is more maintainable also depends on the makeup of your team. If it's primarily a bunch of Java/C# programmers, than the former style is best.

On the other hand, if you have a set of string programmers and a bunch of domain experts, the DSL style is not only faster but wait to maintain. Your core programmers should be good enough to deal with both the host language and the DSL with no difficulty, and your domain experts need only to understand the DSL, which could be easy since it's already optimized for their domains. I've certainly read about this approach being very successful with Haskell at a bank.

More generally, core logic should be easier to understand and maintain with a DSL. Perhaps this makes it harder to extend or repurpose the DSL without a good understanding of the host language and the codebase, but it makes working within the domain much easier, and makes it simpler to verify that the code is correct in regards to the specific domain.

Also, Javascript is not the best language for embedding DSLs; while it's not horrible, the syntax is inflexible and the semantics are somewhat limiting.


While conventions are useful, different conventions are appropriate for writing different kinds of code, and one should use the right tool for the job. Understanding code written in a functional style is something a good developer should be able to do for the same reason that recognizing design patterns in use is something a good developer should be able to do.


Many of the business rules I've seen would be (and often are) better handled by rule engines; and these tend to be functional or functional reactive in nature.

There's usually lots of complicated conditions; if the customer is grandfathered in, then apply rules R1, if they got discount X, apply R2X, otherwise apply R2. Then a new set of rules come in and you need to grandfather the old ones in, and so on; the conditions grow like weeds. When you have rule engines designed around decomposing these conditions, they make them easier to develop, test, they can do things like warn you when certain cases are impossible to reach, etc.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: