Oh, it also helps me to pay my bills, because someone has to untangle the mess.
And it helps my therapist, because he has to keep the madness that grows inside of me in check.
Jokes aside: I was taught OOP at university.
I was also taught functional programming, answer set programming and other forms such as logical programming.
Focus was definitely on OOP though.
I mainly see OOP as a way to (dis) organizer code and a way for hardware manufacturers to sell more hardware.
In reality this seems to make coupling even worse. Now you have to dig 8 classes deep just to find the business logic for a particular feature. Changing it is even harder because the rest of the program expects this part to behave in a very specific way.
Rigid class-based inheritance (especially multi-inheritance) is what sucks. This over-engineered complexity really only benefits things like window toolkits where you want super rigid modeling of widget types. But even that's a stretch.
Traits do OOP the right way. Complete flexibility.
Dog goes "woof"
Cat goes "meow"
Bird goes "tweet"
And mouse goes "squeak"
Does not need classes.The "behaviours" being modelled here were data access. Writing .name() instead of .name.
You can save yourself the time of manually packing these structs by writing out a constructor in full. Which the article called "automatic".
(You don't even need to write out the constructor for a struct in C99. Probably any other modern language too)
No, it won't. I'm especially sad that this, like so many OOP guides before it, did not go into how it interacts with data structures and bigger picture stuff. It had the perfect chance to do that as it could have made a Catalog class and then had a discussion about what belongs to that and what to the books. Instead it started to abstract on author, in the stupidest way possible (no, no one will ever look up a book using the author birth date).
It's incredibly difficult now dealing with zoomers in the workplace that think I'm some old boomer that never learned "proper computer science".
No, sorry Timmy, it's not because I don't understand microservices, it's because I actually do.
What people forget -- much like the design patterns in the gang of four book -- is that languages and frameworks evolve.
A decorator pattern was a niche but useful abstraction in the 1990s. In Python today you can @decorate stuff just like that. It's evolution.
The same holds for OOP. Encapsulation and co-located methods with the encapsulating slots was an incredibly powerful upgrade over basic structs. Now most languages have first-class functions and lexical scoping so you can build your own encapsulation that way.
It's all good. Just use whatever fits best.
Most complex codebases I've seen which were pure Functional Programming were spaghetti code; unmaintainable.
What I saw every single time was that the project was syncing a huge amount of state in a central place and then passing it through a large number of components and sub-components. The top level component basically had to have full awareness of everything going on inside the system in order to do its job and there were no separation of responsibilities because none of the components had sovereignty over the state they needed to do their job independently. It's just components micro-managing components all the way down.
React with Redux is probably the best FP implementation I've seen thus far but even it is kind of a mess. I have nightmares about Redux Saga. The Redux Saga logo is literally a stylized drawing of entangled spaghetti.
Had Redux + Saga been presented to people as part of React at the time it was introduced, React would probably not have become so popular. Because people would have understood that it creates too much unnecessary baggage which isn't worth it. React was used as a gateway drug to Redux which was itself a gateway drug for Saga!
to me the best way to design large systems is sort of like an ecs. you don't separate components by state + behaviour, you separate systems and state.
I see it with OOP, XML, design patterns, and other things, now with LLMs. (LLMs - you really want to build complex systems in badly specified natural language, compiled or interpreted with an inscrutable algorithm and possibly indeterministic?)
Is it the excitement from a new analogy? Or are engineers naturally empiricists, while the rationalism/empiricism distinction doesn't work in computer science?
I think we would be better off if we just learned functional programming and few abstract concepts (categories, monads). Simpler than OOP.
The thing that empowers first-class functions and closures (lexical binding) is the exact same method by which encapsulation works, even if the latter opts for heap vs stack. The fundamentals are the same.
Here's a simple one in Emacs Lisp:
(defmacro send (object method &rest args)
"Sends a METHOD to an OBJECT with ARGS."
`(funcall ,object ',method ,@args))
(defun make-animal (name)
;; 'hunger' is entirely private (encapsulated)
(let ((hunger 5))
;; here's our lambda using lexical binding
(lambda (method &rest args)
(cond
((eq method 'get-name) name)
((eq method 'feed)
(setq hunger (max 0 (1- hunger)))
"Yum!")
(t (error "Animal does not understand: %s" method))))))
(let ((good-boy (make-animal "Rex")))
;; "call" (via our macro) the "get-name" method; then feed. hunger does down 1.
(send good-boy get-name)
(send good-boy feed)
;; pretty-print the "object" good-boy
(pp good-boy))
;; this is the state of it after the two calls.
#[(method &rest args)
((cond ((eq method 'get-name) name)
((eq method 'feed) (setq hunger (max 0 (1- hunger))) "Yum!")
(t (error "Animal does not understand: %s" method))))
((hunger . 4) (name . "Rex"))]What you are describing is OOP. Passing messages between identities over calling pure functions with values.
Isn't one of the tenants of FP that nothing is mutable anywhere?
But I also spent some time with modern Spring Boot, and I get where the hate is coming from. There is a lot of complexity that just doesn't seem necessary at all.
We're collectively shaking a lot of trees when we build frameworks, languages and tools. What works? What does not? What is the right level of abstraction? How much developer ergonomy do we want to sacrifice?
Sadly we only seem to know in hindsight what works well. But that is also how we learn and grow; it was just meant to be this way.
The point is not to be snug about it. Functional programming (and monads) are actually simpler. You just need to resist the urge to "make it more understandable".
Abstract math doesn't have good analogies to the real world. By trying to make an analogy with the concrete ("monads are mappable") you lose simplicity.
I'm sure there is some (very high) level of inherent project complexity where the massive number of abstractions and tools that Spring Boot gives you (and forces on you) actually starts turning into a net positive... And I'm also fairly sure that most projects don't quite break even, and would be better off with something more lightweight.
eru•1h ago