I wrote a little, here and there, about the so called F* meta-pattern. I created F* to close a bag of worms. However… …F* is merely a minority report. A kind of footnote to MVC.
In the grand scheme of corporate front end development, MVC stands out for super-structure. To begin with, it doesn’t take a genius architect to work out labour separation. We named Max, Vincent and Connie. How many Frogs would it take to maintain an F* app?
Incidentally, the bag of worm re-opened when I tried to explain the command pattern to a new recruit, and got a poor old MVC natural on my doorstep the next day.
What would you do? Rewrite the whole thing? I didn’t. I tried fixing it up. Now’s a time for rambling and recriminating.
Post-scriptum
OK then. This post is about MVC the way people do it ‘their own way’. Without using frameworks, and without using the command pattern. This post doesn’t contain answers. It’s just listing lazily a lot of scary/worrying/time consuming issues.
Command patterns and frameworks have one thing in common. They’re a little heavy. Heavy can mean a lack of concision and elegance. It can also imply conceptual overhead. Heavy can also cover an element of cultural difference. Either way…
…heavy isn’t for everybody. I didn’t write heavy code when I was 17. I did write some cool stuff though, including stuff I would only half-guttedly replicate today. So this post is raising an issue: can we still just write a little bit of code, and get away with it?
Finally, before you read away, be assured this isn’t a spoiler. If you want to do your own MVC stuff without a command pattern and without a framework, it won’t protect you against unpleasant surprises.
May refactoring be with you.
It all started with a view, a model and a controller…
Back when I started ‘doing MVC’…
- Write a *Model* class containing a few bites (no bits, no bytes) of data.
- Write a *View* class batching a couple of widgets.
- Write a *Controller*. The controller instantiates and refers the *View* and the *Model*.
- Let the controller listen to events from the view and the model.
- In response to view/model events, let the controller update the view and modify the model.
Really doing it
If you really are doing MVC the wild way (or maybe just writing a moderately sizable app) then you’ll need to go a little further:
- Writing components. For lack of a better word, I refer to ‘mini-apps’ – bunches of MVC classes that work together to realize a feature in a larger app – as ‘components’. Components needn’t be hard to write, and in theory the ‘scaling up’ question needn’t interact with whatever well-formed approach to MVC we’re using (why? because either way the secret is to keep components decoupled. A ‘keep the bags of crap small enough’ idea that I’ve been pushing forward in my posts about F*).
- Writing ‘models’. I hope you’re not trying to get your way around TableModel, ListModel and other API induced models, and how they should fit in our MVC collection. Because I am, and I wish to be enlightened.
- Keeping it small and simple. We don’t want our apps to grow any bigger or more complex than they ought to be. Or do we? Unfortunately trying to keep front ends manageably small is a good way to make them unbearably intricate. At the other end of the scale, fixing the same bugs in countless apps ‘prototyped one another’ resurrects Taylorism.
Before things go wrong
Before things get really nasty, here are the tell-tal signs that might finally help us understand what to do with our MVC naturals.
Getting confused and arguing over it
When I started with my 3D engine, I considered that 3D assets were view. Unfortunately, 3D geometry affects game logic. Sometimes also, 3D assets are adequately used to hold data that (I think) ought belong to the model. Some guys quickly judge this kind of situation and get over it. Your colleagues from the front end get into heated discussions about what goes in the M or V or C. You think it’s a waste of time and you’re perfectly right. If there’s no hard business/real world constraint driving towards a correct answer, it’s like naming a baby can get. Oh my.
What is the controller?
I felt immensely relieved when I heard a colleague say this for the first time. Here’s why. Because every so often, the view is specifically written for the model. Most of us understand why you would want to change/write a different view for the same model. Many of us acknowledge that views are disposable app-fodder. Views are ad-hoc. In short, the view root can listen to widget events and effect model changes directly. So why do we need a controller?
Why we cannot write clean components.
Because the UI is bullshit, or the UI is bullshit.
If you give the UI work to a UI designer, they’ll think about usability. They’ll make a UI that has weird shortcuts. The component hierarchy won’t match the model’s functional hierarchy. In short, the UI won’t map your model closely. If it’s a good UI, it will even get literally (legitimately) intricate. Meaning that the hierarchy will be unclear enough that you won’t be able to ‘just take a component and drop it into another app’. Business apps should be more tractable. That’s because…
Usability is irrational bullshit. Unfortunately business apps also are bullshit. They are boring, slow to use and un-fun. That’s why people are paid to use them.
What are view states?
We’re writing an app allowing people to choose shirts. Shirts come in different colors. The UI designer suggests that the ‘add’ buttons in the shopping cart should match the shirt colors. What’s going on?
This is just a silly (and actually, redemptory – the ‘color state’ is blissfully captured by the natural data model) version of the model-view/view-model dilemma. View has states that aren’t perceived to partake the model. However such states can be linked to the model, and more often than not, these states also persist in real apps (as in, real-world apps persist their UI states). Here are three perspectives on the situation:
- If it’s a variable, it’s a state. State belongs to the model. My first tech lead frustrated me a little by implying this is obvious. Is it obviously right to conflate the data, or (as he suggested) whatever is the data model (4th tier alarm!) with cosmetic stuff like font size, colors and alignments?
- Add view.model, view.controller, view.view to your view package. Call a cat a cat. While this may seem logical, it needn’t take us very far. If we’re not serious about our view, that’s OK. Otherwise we’re reducing separability in unpredictable ways. Most apps do MVC just to keep things neat and clean. If separability has business strings attached, there will be a price.
- Don’t confuse data and model. More specifically, don’t confuse the view model and the data model. That’s a weird avatar of (1) and I don’t want to be sure what to make of it.
Is my controller holding state?
Yes. That’s a prime rule for a well formed MVC instance (an app written using MVC). The controller should hold no state. I would be so very delighted to announce that controllers cannot declare fields. Err, I’m afraid we started off declaring a view and a model field under our Control class. I’m sure you don’t think we are doomed yet.
But it’s not over. Now we’re ready to add ‘control states’. We’re also ready to write state machines. Yuk, see below.
I know you know. Call a rabbit a rabbit. These are states which belong to the control layer. Let’s add a control.model package. Unleash the Geek Inside.
Hyper-hacktivity
MVC naturals are incredibly hackable. That’s one of the things that got me writing tonight. I’ve been hacking an MVC instance mercilessly for 10 hours nigh. It’s very neat, because I spent three days this week trying to ‘rehabilitate’ the same app. Now I feel ready to start over. It’s good to be able to sort things out and release on time. But if I save one day every time I waste three, how good can it get?
Thinking about it, here’s one reason why MVC naturals are so hackable: statemessness.
- Your GUI library is object oriented. It’s full of weeny controls that duplicate model state.
- Your model is the primary state-holder. Surely the model knows (nearly) everything.
- Your controller wouldn’t be so easy to write if you didn’t buffer a little state here and there.
Hackable. No matter where we’re writing code inside an MVC application, no state is ever far from us. Maybe not quite the right state, yet, in a first (and durably misleading) approximation, just about right.
Don’t hide behind your framework
MVC frameworks do that. If you look into their implementations, you’ll find that rules get broken. Basic rules. I see three solutions:
- Rules are for n00bs. The powerful magic behind singletons, static, event broadcasters and (while you’re at it) the C pre-processor is trickery that everyday coders should be interfaced with / insulated from, not exposed to.
- MVC frameworks are bad.
- The rules are bad.
Unit-testable or clear and concise?
I’ve been trying to put some of my latest MVC natural under unit test. Since I’ve been trying, and trying often leads me to explicit stuff I’d rather, for the sake of clarity, didn’t show up, I feel that natural MVC is biased against unit tests.
Inter-act
STOP.
By now, if you’re still reading you should probably go for a coffee break. Trust me. After all this article is just food for thought, not very thoughts.
Nice to see you back. Now that I’ve dusted around a little of the dust in the dust-bag, let’s muse a while into the muddle-dy swamp.
How things go wrong…
The shortest path is never the best path
Here are a few examples:
- It’s faster to emulate a button click than to separate action from reaction. The play button starts playback. The play menu item also starts playback. I want exactly the same thing to happen when I press the play menu item and when I press the play button. Sooo… I hack something up to pretend the play button was pressed when I hit the play menu item.
- It’s nearly always faster to pre-empt view updates. The controller knows what the view wants to do. The controller knows what the model will be like after we change it. In fact, the controller needn’t read the model, because the view reflects the model state faithfully enough… especially when we get started off and our view/model mapping is simple. I remember decomposing roundabout VCMCV routes using powerfully soporific sequence diagrams for the sake of principled colleagues. I also remember breaking my own rules and trying to explain what kind of risk is involved using whatever shortcuts.
Now that I think about it…. (gasp) we don’t even need to update the model every time. That is, until auto-save stores a half-baked image of our data.
Back to the original point: do we need a controller, or a model? Do we even need classes? Why not just use punchcards?
- Re-writing it is faster than just using it. MVC naturals tend to generate hierarchies. These hierarchies, more often than not, connect on an ad-hoc basis. Lay it out in UML:
“it is 7:50 pm and you want to go home. You are ‘here’. The function you need is 10 clicks away on the class diagram and 3 steps are blocked because the hierarchy doesn’t back-wire. Re-write? Use a singleton? Introduce dependencies over 10 unrelated classes? Expose your lack of style and insight (russian doll message passing)?”
My button back-fired
Here’s a list widget. The user selects an item. A view event fires. The model updates.
Here’s a list. The list selection gets remotely updated. A model event fires. The list widget gets updated. A view event fires. The model gets updated. A model event fires…
Why is this happening all the time?
The inheritance delusion
It’s a text-book truth that inheritance isn’t an implementation level commodity. That’s probably why inheritance is hailed as a technique improving reusability and concision.
I took a controller this week; abstracted a base class off it. That simplified my coding four more, similar controllers. How are they similar? Well, they kind of work the same as the first one.
Truth is, I did it to save time and clarity. I’ve also seen what happens when we keep at it. Controller code isn’t especially concise. App controllers are meaningless idiosyncratic beasties anyway. Not your rationally bound mammal to mouse to cow inheritance anyway. If an app controller is a meaningless idiosyncratic beastie, what would an abstract app controller be? Or its grand-grandson?
Before you know it you’re abusing the decorator pattern. Classes implement functions for no reason, and nobody can understand a derived class until they’ve mastered five ancestors up the chain.
MVC naturals make it easy to use inheritance in this way. Or is it just inheritance that’s easier than delegation?
Your controllers are cursed down to the 13th generation. Amen.
The state machine delusion
Controller states are non committal. Unlike data-grave entries. Unlike serializable model data. Unlike view states, which at least, get rendered. Add a little flag here. Add an enum there. It doesn’t matter if two controller state-holders describe overlapping state. It can only hurt a little.
Here we are. It’s ‘kind of like a state machine’ just less complex and more complicated at the same time. However, all we need to keep ahead of it is a really good debugger. Well, I’d rather go and sink my own boat.
Until next time
It’s nothing like I’m done. I’m expecting staffing this experiment. As I stated at the beginning, there are many reasons not to go heavyweight. So I still need to find a way to get us sitting atop Pandora’s box. If there’s a way little bits of code mightn’t spiral out of control, looking for it is helping out, not brandishing glossy patterns no teenage coder would bother with.