5

I have an application where I'd like to add ways for external modules/components to hook during the processes and data-flow and perform actions/modify data.

For the first requirement—performing actions—I assume the best pattern would be to emit events and have other modules/components subscribe to those events and perform their actions, correct?

The second requirement is where it gets very tricky for me, I will try to explain it with an example:

someObject = {
    ... // properties and stuff
    performComputation: function() {
       let data = this.data;

       return this.x * data.amount;
    }
}

Now, I want a way to perform dynamic modifications on some value of that function, and maybe the return value. What I want to achieve is very similar to what WordPress does with filter hooks. WordPress maintains an array of callbacks to call in a certain order to allow for data manipulation. If I implement something similar, my code would look like this:

someObject = {
    ... // properties and stuff
    performComputation: function() {
       let data = applyFilters('computationData', this.data);

       return applyFilters('computationResult', this.x * data.amount);
    }
}

and I could then hook into that using an API which would look like this:

addFilter('computationResult', (res) => { return res * 2; });

This obviously works, but by the fact that I have never seen this pattern used in any JS library and the fact that with hours of research I didn't find anyone implementing a simple node module about that, I have the impression this might be an anti-pattern that I should avoid (I understand it can become messy and hard to debug, for example).

So, here are my questions:

  1. What's this pattern called? Maybe I just don't know how to search for it.
  2. Has this anything to do with Aspect Oriented Programming?
  3. Would there be a better pattern approach that I am not thinking about that would fulfill my requirements? Specifically: (1) hooking into parts of the applications to manipulate data (2) hooks need to be added and removed fairly often during the user interaction with the application.

Edit

It seems that my goal is being misunderstood, so I'll try to explain it better. The Observable pattern or Event dispatching allows me to run code within the execution of another code. However, the reason why it is not enough for me is specifically because Observers don't return values that can be manipulated.

As for AOP, as pointed out by Candied Orange's answer, the target doesn't know it's being hooked on. Which is also not my goal.

My goal is for a function to expose certain pieces of data for other functions to hook on and manipulate.

Again, with another example pseudo-code:

someObject = {
    name: "Jim",
    greet: function(str) {
        let greeting = applyFilters('greeting', str);

        return `${greeting} I am ${name}.`;
    }
}

addFilter('greeting', (str) => { return str.toUppercase(); });
addFilter('greeting', (str) => { return str + "!!"; });

someObject.greet("Hello"); // => HELLO!! I am Jim.

This is the kind of functionality I need, and it can be easily implemented with iterating over callbacks as I mentioned, but I am not sure if this is in any way a good pattern or if I have alternatives to achieve this goal.

3 Answers 3

1

I've written software before that uses the approach you describe from wordpress (interestingly, the software I was working on when I independently came up with the idea was also a PHP CMS system... I wonder if there's something about the requirements of that kind of system that pushes you towards the solution more there than in other environmnents?). I've also worked in environments that use Aspect Oriented Programming heavily (e.g. the Spring framework for Java), and can see that the two are definitely very similar. The wordpress plugin filter approach is essentially equivalent to a manually-implemented post execution pointcut in AOP.

Both are very flexible, easy-to-use ways of introducing customisation potential to your code. But it's very easy to get confused by how the system works -- make sure you keep very careful track of how each feature builds on others and what filters it uses, because you can get unexpected interactions between modules and tracking them down without documentation of what modifies which result can be tricky.

The only other advice would be that if you want to use an AOP approach, why do it manually? There are javascript-based implementations of AOP (e.g. this one), and using one of them could allow you to reduce the replication that you'll inevitably end up with for building and managing your list of hooks and calling it everywhere you need.

0

Hooking, or creating hooks is causing a change the behavoir of software by modifing it's binary code. The target program doesn't even need to be designed to allow this. Where the program used to perform one operation at this location you change it to perform another. That's a hook.

Where this gets confusing is when you start applying this term to source code that does the same thing. A virtual table in c++ is meant to be modified so that calls to abstract functions/methods can be polymorphically dispatched to different concrete functions/methods. Is that a hook? Well yes, kinda, but it's the linker that's doing the hooking, not the source code that asked for the virtual table.

But the world of programming is wild and wooly so don't expect everyone to have as narrow a view of what hooks really are as I do. When someone describes the methods in a strategy pattern as hooks I don't correct them. I just move on.

So when you say you want an array of callbacks I'll grudgingly acknowledge that looping through this set of 'hooks' is equivalent to an object oriented pattern called observer. This is what an event really is. Using this pattern it doesn't mean matter if data is modified on a different thread then the observers (the 'hooks').

Of everything you've mentioned Aspect Oriented Programming (AOP) is the closest to true hooks. The target of AOP doesn't need to have any idea that AOP is being used on it. Unlike inheritance, composition, dependency injection, or even setters and getters, the target of AOP doesn't have to be designed to accept hooks.

However, you're working in javascript. I should warn you that much of what your tossing around comes from the world of java and object oriented programming.

In the javascript world you have better access to functional programming. With functional programming many design patterns simply aren't needed. I'd recommend you look into functional reactive programming. It solves many of the same problems with events but should be more natural in javascript then trying to map object oriented solutions into somewhere they aren't really needed.

1
  • Thanks for clarifying and forgive me if I used an incorrect terminology. As you said, however, the term hook is used in a variety of ways de facto, and I decided to use this word just because the way WordPress (and other CMSes) use it, it's basically my goal. I think I might have incorrectly explained my goal. Instead of adding on a comment, I'd be grateful if you'd check out my Question Edit. Commented Aug 5, 2016 at 16:58
0

One of the best articles I've read on this subject is by Ebay, here:

http://www.ebaytechblog.com/2014/10/02/dont-build-pages-build-modules/

They describe how they'll use jQuery as an event dispatcher to communicate between discrete modules. But they also suggest an alternative would be to use a dedicated event mediator to coordinate the events of all the different components.

Of course modern frameworks like Angular and React/ Redux have somewhat opinionated but tried and tested ways to have communication between between parts of your software. I would spend a lot of time investigating all of the modern JavaScript frameworks, SO MUCH has changed recently.

1
  • Thanks for the answer, it was a nice read; however, this deals mostly with the first part of my question: event-systems as hooks. The thing with events is that the code that triggers them rightly doesn't care of who is subscribed; as such, events don't return values that can be passed around and manipulated. In my case, I need a way for other parts of the components to "filter" around specific data exposed by a specific component. As far as I know, this is specifically not allowed inRedux for good reasons. That's why I was also asking for an alternative, since this may be an anti-pattern. Commented Aug 5, 2016 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.