PAC, Never Goes Away
When you have an interview and you ask someone about patterns and they say ‘I‘ve used MVC of course,‘ you know you are dealing with someone whose concept of pattern is the complete anti-definition of the whole reason for being of the patterns movement. The Alexander ideas are all about applying things, and this requires knowing the dynamics of what is being applied, because there is always a process of interpretation Most people, when you talk about MVC, think ‘wait, interpret what? model is where the data is, then the view has the ui.‘ I have posted a lot of times before about how MVC falls apart. Today I thought of a new way to schematize this:
- If you have a simple 1:1 between the view and model, then you are fine with MVC. Of course, logically speaking, there‘s not a lot of reason to brag about separating things that don‘t have any other connections. But at least you can tell people you followed the pattern.
- Then comes the classic MVC boast: 1:M. The best super example is you have an editor. You want to show the text in Unicode and Hex. You have one model and you have 2 views. How often does this happen for you? Almost never is my answer. Furthermore, I subscribe to the argument that having 2 views reference the same model is clearly not object oriented. Most people end up breaking their multiple views into a series of 1:1s: the table view, then the detail view, etc.
- Finally, you get M:M, or chains of 1:M or maybe a hierarchy of 1:Ms (tree structure). This is where MVC really falls apart.
So if you knew you were going to end up at stage 3 from the beginning, you could choose another approach, but no one ever does. This is another problem with MVC: it‘s kind of a roach motel.
I looked at some code this past week that had been expanded: super simple concept: we bring a bunch of things in from a feed, then people thumbs up or down those things and they move into their queue and/or a company queue.
Using MVC, you have a couple choices: each one is its own model, with a corresponding view. Which is what had transpired in our code. But one of the core problems there is that when classification events occur (thumbs up/down), you have to have all the views update themselves from their models. This is costly and stupid. Each view has to go rerun its core query, when in reality, you could write a tiny snippet of code that could make things right with all 3. How? and where would that go? Enter PAC.
The two core concepts in PAC are that components very often need their own abstractions (hence the PAC, presentation-abstraction-controller), and that those components very often end up in hierarchies where updates to the abstractions can be done by the individual controllers at each node. The only remaining question is how do they know when and what to update. The answer is simple: an event occurs and they are notified.
So in this case, each of the individual views has their own abstraction, and the controllers at each node implement the listener interface. Then when the user clicks on thumbs up or down, the coordinator is notified and the coordinator notifies all the listeners. If you voted something up from All, it should be added to My and Company. If you voted something down from All, My and Company can check to see if they have them. If they do, it can remove them, etc. Ironically, in a world where engineers constantly claim they couldn‘t do the right thing because performance would have suffered, most applications still almost always model views as merely ‘what‘s in the database right now.‘ And then when performance comes calling, start doing stupid regressive things to decrease the pain.
The other thing that‘s kind of interesting about this case is that the view is pretty much the same, it‘s the models that are different. This brings up another interesting advantage for the PAC camp: view reuse. The PAC version of this code is so much simpler, and the coordination of the updates is so confined, that you can imagine that 90% of this approach can reside in abstract classes that could be reused for a model where the items being classified are totally different (perhaps through generics).