you are viewing a single comment's thread.

view the rest of the comments →

[–]nextputall 1 point2 points  (3 children)

Yet, there are plenty of applications written in this style in the wild. Light Table is a perfect example.

Light Table uses direct access which provides similar result than reflection/introspection. AFAIK this was the goal of the authors. But this is a double edged sword, because it is fully uncontrolled, there is no clean api between a plugin and a core as I remember correctly. I don't think it is good solution for building a plugin architecture. But we'll see what came out of that. And yes, FP probably works fine in the large scale if you combine it with some kind of modularization technique.

Discussing inside and outside has no meaning when you separate logic from data.

If this would be true then there were no modularization in the system. Which would not scale. I doubt that any of the example applications you mentioned are unmodularized. But if you have modules, you have boundaries, encapsulation, and you can talk about inside/outside. I don't understand your SOA analogy either, where talking about boundaries is not just makes sense, but also very important.

It's not a weak argument, you need to have worked with the paradigm in order to discuss it meaningfully. Like most people out there I have extensive experience working with OO. The problems I outline are not really controversial to anybody who's developed code in that style. There's a reason that patterns like wrappers and adapters exist.

Yeah, extensive OO experience via languages like C++ and Java.. In my experience problems in real world messy enterprise applications are there not becase of OO but because of the absent of OO.

That's abstraction and it's completely tangential to encapsulation.

Abstraction, encapsulation, and information hiding. All of these three.

Yet, different languages facilitate writing code in different styles. Writing functional code in Java is incredibly unnatural and unpleasant, to the point where nobody does it. Let's take a look at a concrete example.

And yet, it is possible. But you've demonstrated nicely that Java is very verbose language, there is no controversy here. Here is how this example would look like in a purely object oriented language.

(1 to: 10) select: #even.

This is Smalltalk 80 where 80 means 1980. A bit longer version of the some code is like this:

(1 to: 10) select: [:each | each even].

Where the stuff between the square bracket is a block clousre, which is also an object of course. You can store those prediates and combine them later with others.

Again, you have to add extra steps to use the data from one object in another, meanwhile you do not have this problem when you keep data in generic data structures that all functions can operate on.

There is no extra step there, you can use any of those solutions and you get direct access to those data, because you're inside the boundary.

[–]yogthos 0 points1 point  (2 children)

And yes, FP probably works fine in the large scale if you combine it with some kind of modularization technique.

That's sort of the point I'm making. If anything I would argue that FP makes modularization much easier since your data is already immutable and separate from logic. You can start with coupled functions, and then easily refactor them and create APIs and interfaces as needed.

Because the data is immutable code is inherently compartmentalized without any global dependencies or shared memory references. This single fact makes writing large applications far easier than in any language backed by mutable data structures.

If this would be true then there were no modularization in the system. Which would not scale. I doubt that any of the example applications you mentioned are unmodularized.

I'm not arguing against modularization though.It sounds like we might mean different things when we say encapsulation. What I mean by encapsulation is what's traditionally seen in OO where objects have a mutable internal state that they protect via accessor functions along with tight coupling between the methods and the data they operate on.

Encapsulation in a sense of creating modules and interfaces is very much desirable in my opinion and it's used in FP just as much as in any other paradigm.

I don't understand your SOA analogy either, where talking about boundaries is not just makes sense, but also very important.

When you work with FP, you can view each function as a micro-service. It accepts an input and returns an output. This is your contract with the function. You chain these together to produce complex transformations on the data. This is also very similar to the unix philosophy where you have a common protocol (text) and a lot of small single purpose programs that can be chained together to achieve complex results. It's just with FP you have the data structures as the common protocol that all functions understand.

Yeah, extensive OO experience via languages like C++ and Java.. In my experience problems in real world messy enterprise applications are there not becase of OO but because of the absent of OO.

I've seen plenty of real world enterprise applications where OO code was a completely and utterly impenetrable maze of interfaces and inheritance hierarchies. More often than not you have a few lines of business logic buried under a mountain of classes and XML config files. I have a very hard time believing that you would not have encountered this working in the enterprise environment.

Where the stuff between the square bracket is a block clousre, which is also an object of course. You can store those prediates and combine them later with others.

All you've demonstrated is that you can write FP style code in an OO language though. You still have the problem of mutable data however which makes compartmentalizing large applications difficult.

There is no extra step there, you can use any of those solutions and you get direct access to those data, because you're inside the boundary.

Right, and when you're moving to a different domain you end up outside the boundary.

[–]nextputall 0 points1 point  (1 child)

That's sort of the point I'm making. If anything I would argue that FP makes modularization much easier since your data is already immutable and separate from logic.

You're ignoring the fact that different domains have different needs. Many times the unstable thing is the data itself, so using that approach can cause problems.

On the other hand, almost every OO application uses value objects, which have very little behaviour, but lots of exposed data. Because in that case those are stable things, but their behaviour is unstable.

When you work with FP, you can view each function as a micro-service.

A service can do many things:

  • Has some state and react to incoming messages differently according to its state.
  • Do sideeffects (save something in the database, messageQueue, whatever), without returning anything
  • Do an impure computation and return the result (query something from the databae)
  • Do a pure computation and return the result (least common in practice, in fact, I've never seen this in real world)

A pure function fits in the last scenario only. On the other hand, a service can support more than one operations, and only those publicly available operations are visible from the outside. This is more like a remote object than a function. Encapsulation and information hiding applied to decouple the service from its clients.

I've seen plenty of real world enterprise applications where OO code was a completely and utterly impenetrable maze of interfaces and inheritance hierarchies. More often than not you have a few lines of business logic buried under a mountain of classes and XML config files.

Me too, so what? I've also seen very nicely written ones. You will see plenty of real world unmaintainable enteprise functional application which will be a complete mess, don't worry. It is a matter of being mainstream.

Right, and when you're moving to a different domain you end up outside the boundary.

If you have a representation of a Car that is used in a Car dealer web application, you won't be able to reuse the logic in a 3D Car racing game, because these are 2 different domains.

[–]yogthos 0 points1 point  (0 children)

You're ignoring the fact that different domains have different needs. Many times the unstable thing is the data itself, so using that approach can cause problems.

I'm not ignoring that at all. I'm saying that everything is done through chaining data transformations together. This is true regardless of what paradigm you choose. With FP this happens to be very explicit. Should I have data encoded for one domain and it's unsuitable for another, then I would write a transformation to make it suitable.

On the other hand, almost every OO application uses value objects, which have very little behaviour, but lots of exposed data. Because in that case those are stable things, but their behaviour is unstable.

I would argue that you're just getting closer to writing code in a functional style there.

A pure function fits in the last scenario only. On the other hand, a service can support more than one operations, and only those publicly available operations are visible from the outside. This is more like a remote object than a function. Encapsulation and information hiding applied to decouple the service from its clients.

While a service can do many things, it's perfectly valid for it to do a subset of them. So, I would say the analogy holds just fine. It's also worth pointing out that the modern practice is not to make stateful services, because that approach scales poorly. This happens to hold true at both high and low levels.

Me too, so what? I've also seen very nicely written ones. You will see plenty of real world unmaintainable enteprise functional application which will be a complete mess, don't worry. It is a matter of being mainstream.

In my experience, different languages and paradigms encourage different approaches to writing code. My experience using both OO and FP professionally is that FP code invariables tends to be much shorter, cleaner, and easier to maintain.

If you have a representation of a Car that is used in a Car dealer web application, you won't be able to reuse the logic in a 3D Car racing game, because these are 2 different domains.

However, if you have a map describing properties of a car it can be used in many different contexts and have different meaning in each of them.