5

Are there any obvious flaws to this OO architectural model which I intend to implement using javascript? It is similar to the MVP model but instead the role of the model is broken down into three modules:

  • the cache (stores data instead of rerequesting from server)
  • the model (manages requests for raw data, retrieving it from the cache if available or the server)
  • the modifier (handles requests which require data which makes changes to the data on the server)

For a diagram showing how data flows through this model:

enter image description here

view

  • sets up & manages the UI possibly requiring the requesting of data from the presenter
  • sets up controls to alter what is displayed, possibly requiring the requesting of data from the presenter

cache

  • contains a record of some fetched data in data objects
  • has a .store() method for storing data in the cache
  • has a .retrieve() method for retrieving data from the cache
  • access for storage and retrieval is available to the model and the modifier (acting as a faster intermediate location for the sharing of information than the server)

presenter

  • handles requests for formatted data from view
  • requests data from Model (passing a callback for completion) formats data for presentation and calls view callbacks

model

  • handles requests for data from presenter
  • requests data from cache (cache.retrieve())
  • if data not in cache, requests it from server and then stores it in cache (cache.store())
  • data passed back to presenter via callbacks

modifier

  • handles requests from view for modifications to data
  • specify post, put and delete request types
  • only support specific types of request which may be handled separately (eg settings)
  • stores new data in cache (cache.store())
  • pushes data to the server
  • calls callback about the success of data storage

This is quite big project and there will be a number of others working on it so it would be good to get it right from the off.

edit 1

The cache.store() and cache.retrieve() methods both only receive the information required to refer to the data in the cache, but do not specify how it is stored. The cache methods use this information to respond with or store the correct data, but the internal structure in which the data is stored is kept secret.

2

Alright, you're editing as you go so let's walk through what I'm currently seeing:

So a user selects something in a combo box triggering behavior to fill in the contents of another combo it's connected to.

The view requests data from the presenter with an ID(s) for the data and something identifying the combo needing to have its contents refreshed so the presenter knows who's asking so it can set up the callback to give the formatted data to the right object.

The presenter requests data from the model with the ID(s) for the data and a callback for formatting that data.

The model requests data from the cache with the ID(s) for the data. It either immediately returns data it already has or it requests data from the modifier with the ID(s) for the data. It ultimately gets that data and fires the callback with the data as an arg which ultimately formats and hands it to the widget that needed it.

The big question for me... Why are you passing the same argument 3-4 times before anything actually happens? That should smell bad to you. Very bad. Any time you pass the same arg twice in a non-currying type scenario, you should take a whiff. If two objects need to act on the same argument, they should exist as components of another object.

Why does anybody but the combo view need to know what other combo needs the formatted data? Why should anything outside of the combo view know how it's supposed to format data for the view? Why should more than one top-level object be handed the ID to ultimately get the data?

As I said earlier:

I think you're breaking out subdomains without really needing to.

Model makes sense with cache and modifier inside it. Nothing else need be bothered with the details of how those two work and that general model object is also a good place to have helpful methods for adding new types of data templates containing all the data the model components need to implement the new structure and make it accessible/bindable.

Presenter is definitely a subdomain of your view. Converting data to a view-format is one of the primary responsibilities of any view. From a portability perspective this will always need to move with whatever it is that's interacting with HTML in other ways so there's not much point in separating it.

At the highest level I tend to see these three as the evergreen concerns worthy of separating in any non-trivial UI app. There is of course plenty of other stuff you might want to separate for a given architecture. I just see these three as somewhat critical if you're talking about a highly re-usable client-side architecture/framework.

  • Data-structure/server-communication - Imagine you want to pull a white-label-ish make-over on another similar app of a recently acquired/merged company and you can mess with everything except for the requests that ultimately update and retrieve data from the new server whose code is a complete disaster and better left untouched for now. This is where you need a generic interface for updating, binding, and retrieving data that's decoupled from how that data is actually structured and sent to/from the server. Whatever the ajax is doing, however the data is delivered and sent and looks at point of entry, interacting with it should work the same for combo box UI app logic in the new app as it does for interacting with data in the original app. In your case, I'd probably canonicalize the new data to look like the old data at point of entry and then adapt at point of ajax interaction so you can keep using your old caching logic.

  • UI App Logic - This is the layer that buries the DOM and HTML stuff. A server-side dev with minimal client-side expertise should be able to figure out how to implement a widget with this. A controller basically, but I prefer implementing as another event-driven layer whose plain-english non-ui-dev-friendly DOM-agnostic events are triggered from the UI layer so we can leave it intact and just swap the HTML/canvas/svg/whatever layer out under the hood. Here we set listeners like comboObject.newChoice( handler ); so some poor bastard pinch-hitting from the server-side can handle basic implementation if needed and we have clean separation of data and environment concerns. Unless you're adding brand new types of functionality, this should never need to change once it's done and it should be relatively easy to write self-documenting code here.

  • UI View logic - Are we building a combo box in canvas or HTML? This is the thing we'd swap out to preserve everything else in the app for re-use in a new environment like if we wanted to make a tablet mobile app version of an existing desktop oriented site with drastically different layout but serving the same business concerns. Anything that formats data for HTML or sets events for daisy-chaining from DOM to the UI app logic layer lives in here. Nobody should see jQuery anywhere but here unless you're using it's event system for non-dom concerns. It might make sense to have a generic Presenter-like object wrapper in here that you wrap data in for convenience methods that do things like generically convert data structures to lists and tables in HTML format as well as bind data changes to behavior for the widget.

0

There are a few flaws in the design, in my opinion.

  • Both the model and the modifier need to know how the data is structured internally. This will likely result in a duplication of code and/or responsibilities.

    <update>
    For example, you have a Customer object who can hold an Account. Now the model needs to know how Customer and Account are related so the correct information can be retrieved from the database. But the modifier needs to have the same knowledge to be able to perform updates of the data. If there is now a change to allow multiple Accounts per Customer, there are two places where this change has to be applied. This is the kind of duplication I refer to.
    </update>

  • I would have made the interactions with the cache more transparent.

All in all, I would make these changes to the architecture:

  • The modifier makes the modifications to the model instead of the cache and the database. This gives the modifier the same responsibilities as the Controller in the MVC pattern. You might consider renaming the modifier accordingly.
  • Replace the cache with a cachedDatabase, which handles the database connection and caches the results for fast access the second time the data is requested. For the model it should be transparent where the data came from (cache or database).
  • I should have specified that the cache.store() and cache.retrieve() methods both only receive the information required to refer to the data in the cache, but do not specify how it is stored. The cache methods use this information to respond or store the correct data but the internal structure in which the data is stored are kept secret. Personally, I quite like how this approach enables the modifier, the cache and the model to all act as separate modules and there is an option of adding in extra modules if required. Do you still feel your suggested approach would be better? – Joshua Bambrick May 5 '13 at 21:42
  • see the 'alternate' page at goo.gl/xb5Yy - would this data flow make more sense? I'm not convinced that I like the use of the word 'controller' since I feel this suggests that it sets event handlers for the view (which is not the intention since I felt it would be better if the view could be kept totally separate). Instead, as I see it, the purpose of this module is to receive commands to post/put/delete data (regardless of the source, currently just handlers in the view) and ensure these requests are logical. – Joshua Bambrick May 5 '13 at 21:55
  • doing this effectively removes any purpose for the model, since all it does is receive requests from the presenter, request that data from the cache and then pass it on. for this purpose, I have renamed the presenter 'model' and gotten rid of the presenter – Joshua Bambrick May 5 '13 at 22:10
  • sorry for all these comments, but since the data object is essentially taking on the database interaction jobs of the model and controller, essentially what I previously called the cache becomes a secret module of the data object (okay, maybe I should rename that but cachedDatabase didn't seem very catchy) and the components which were moved into this module from the modifier and the model could themselves remain separate modules which interact with the cache as before but from within the data module. – Joshua Bambrick May 5 '13 at 22:16
  • @Josh'Bambi'Bambrick: First of all, what I write is not gospel truth, but just some advise. You don't have to follow it and you don't have to take it literally. As I am not familiar with Javascript, it might even be that some of the thing I write are not even applicable to your situation. – Bart van Ingen Schenau May 6 '13 at 8:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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