Hacker News new | ask | show | jobs
by jdw64 33 days ago
After reading this post, I got curious and went back to read the original AOP paper. What the OP argued feels like just top-down design. These days, the term 'SPEC-driven' is trending, but it seems like just another word for top-down. They're probably just rebranding it because top-down has a negative image.

Originally, AOP was about separating cross-cutting concerns by centralizing them in one place. It used weaving to separate infrastructure code, and implicitness was inherent in that approach. But the books I read back then said this led to 'ghost code.' It inevitably introduced unpredictability because the behavior wasn't visible in the code. And from a programmer's perspective, that becomes a problem when things break.

On top of that, while the cross-cutting concerns are centralized, they still end up being tied to the framework's syntax, like Spring AOP's Join Point syntax, so they become dependent on the framework itself.

That's why DDD became popular as another way to address OOP's limitations. DDD keeps the business logic pure and framework-agnostic, and that's where things like POJO emerged. At least that's what I read in books, just different approaches to the same problem.

AOP was first presented at ECOOP in 1997, and DDD is usually associated with Evans' book. Both are ways of handling OOP's complexity, but the article here doesn't seem to talk about problems with cross-cutting concerns, which is the core of AOP at all. And this is something AI doesn't handle well. AI makes the most mistakes with implicit knowledge.

Or maybe I'm wrong because I've been studying programming history through older books and have outdated knowledge. Maybe AOP has evolved since then.

What makes it difficult to talk about specific 'oriented' paradigms in programming is that as history moves on and certain problems get solved, if you bring up an older version, you'll get pushback from people who really know their stuff.

'That's a problem that was solved 5 to 10 years ago.' 'That issue has evolved and been covered in other books.'

So it's hard to talk about any 'oriented' approach because you have to specify which era's version you're referring to. For example, even with OOP, which everyone knows, there's a big difference between Smalltalk, C++, and the modern emphasis on composition over inheritance. Someone might say, 'Modern OOP is centered around composition and value objects — you're behind the times.'

AOP might have also evolved and introduced different solutions since then.

So while the perspective on a given 'oriented' paradigm does shift over time, it's really hard to have a conversation about programming because it all depends on which era the programmer is from and how far their knowledge goes.

That's why lately I've been thinking about problems and the approaches used to solve them, rather than focusing on the 'oriented' labels. I wish someone would write a history book about these paradigms. They'd get a lot of criticism, but for programmers like me, it would be much easier to understand.

Sometimes I think it's about time someone wrote a history book on programming

2 comments

I went to an AOP talk by Kiczales back in 2005. When he presented join points as being driven by regular expression matches on identifiers (e.g. Get*: for all methods starting with Get) I decided to heckle. Knowing he has a Lisp background I brought up how Lisp teaches us that symbols should be treated as atoms; good programs don't break atoms apart. I think he made some Lisp joke and brushed it aside. But it's actually an incredibly bad idea.

- Want to add a new method? Maybe it's covered by an existing joinpoint expression and pulled into a pointcut, before you've even written it.

- Want to rename something? Where is it referenced? You can't just search for its name as a whole-identifier match, but must find every join point expression that could contain a regular expression match for it, and then filter out those whose other conditions don't match (wrong class, or whatever).

It is really hokey; and AOP tooling is possible without it, just more cumbersome.

E.g. we can have a special annotation which indicates that method is a joinpoint target, written somewhere on the method. That annotation can list the pointcuts to which it belongs. That becomes more maintainable. The reader of the code knows that since the method is a joinpoint, it interacts with certain pointcuts. They are listed by name, so you can jump to their definitions. When someone adds a new method to that class, they will see that the existing methods have this cruft on them, and decide whether to crib it, and how much. Just because the new method has a certain name doesn't mean it should be in those point cuts, or maybe not all of them.

> it should be in those point cuts, or maybe not all of them.

I really enjoy hearing these kinds of war stories from senior programmers. I don't have a LISP background, but having learned Haskell, your point resonates perfectly.

In the Haskell mindset, letting string-matching rules alter the actual semantics of a program is fundamentally wrong. (At least, that's how I'm interpreting your LISP analogy since I don't know the LISP side well.)

I completely agree with you. Changing the meaning of logic based on string patterns is definitely an anti-pattern. (Though, to be brutally honest, when deadlines are incredibly tight, I've definitely caught myself mindlessly doing it too.)

> So it's hard to talk about any 'oriented' approach because you have to specify which era's version you're referring to. For example, even with OOP, which everyone knows, ...

Ah, about that; regarding OOP, the "that problem has been solved" goes backwards in the revisions. Newer OOP breaks things. As in, "Ah, we have had that problem in Java since 2014, but did you know it was solved in Smalltalk 80". :) :)