The scalability, maintainability and flexibility of an application is mostly determined by the quality of the application’s architecture. Unfortunately, it’s often treated as an afterthought. Proofs of concept and prototypes turn into massive applications, and example code is copied and pasted into the foundations of many applications. You may be tempted to do this because of the quick progress that you see at the start of a project.
However, the time saved will be relatively low compared to the time spent on having to maintain, scale and often refactor your application later in the project. One way to better prepare for writing a solid architecture is to follow certain conventions and define application views, models, stores and controllers before actually implementing them. In this article, we’ll take a look at a popular application and discuss how we might architect the user interface to create a solid foundation.
h3. Code Organization
Application architecture is as much about providing structure and consistency as it is about actual classes and framework code. Building a good architecture unlocks a number of important benefits:
* Every application works the same way so you only have to learn it once
* It’s easy to share code between apps because they all work the same way
* You can use Ext JS build tools to create optimized versions of your applications for production use
In Ext JS 4, we have defined conventions that you should consider following when building your applications — most notably a unified directory structure. This simple structure places all classes into the app folder, which in turn contains sub-folders to namespace your models, views, controllers and stores.
While Ext JS 4 offers best practices on how to structure your application, there’s room to modify our suggested conventions for naming your files and classes. For example, you might decide that in your project you want to add a suffix to your controllers with “Controller,” e.g. “Users” becomes “UsersController.” In this case, remember to always add a suffix to both the controller file and class. The important thing is that you define these conventions before you start writing your application and consistently follow them. Finally, while you can call your classes whatever you want, we strongly suggest following our convention for the names and structure of folders (controller, model, store, view). This will ensure that you get an optimized build using our SDK Tools beta.
h3. Striking a Balance
h4. Views
Splitting up the application’s UI into views is a good place to start. Often, you are provided with wireframes and UI mockups created by designers. Imagine we are asked to rebuild the (very attractive) Pandora application using Ext JS, and are given the following mockup by our UI Designer.
What we want to achieve is a balance between the views being too granular and too generic. Let’s start by seeing what happens if we divide our UI into too many views.
Splitting up the UI into too many small views will make it difficult to manage, reference and control the views in our controllers. Also, since every view will be in its own file, creating too many views might make it hard to locate the view file where a piece of the UI or view logic is defined.
On the other hand, we don’t want our views to be too generic because it will impact our flexibility to change things.
In this scenario, each one of our views has been overly simplified. When several parts of a view require custom view-logic, the view class will end up having too many responsibilities, resulting in the view class becoming harder to maintain. In addition, when the designers change their mind about the arrangement of the UI, we will end up having to refactor our view definition and view logic; which can get tedious.
The right balance is achieved when we can easily rearrange the views on the page without having to refactor them every time. For example, we want to make the Ad a separate view, so we can easily move it around or even remove it later.
In this version, we’ve separated our UI by the roles of each view. Once you have a general idea of the views that will make up your UI, you can still tweak the granularity when you’re actually implementing them. Sometimes you may find that two views should really become one, or a view is too generic and should be split into multiple views, but it helps to start out with a good base. I think we’ve done that here.
h4. Models
Now that we have the basic structure of our views in place, it’s time to look at the models. By looking at the types of dynamic data in our UI, we can get an idea of the different models needed for our application.
We’ve decided to use only two models — Song and Station. We could have defined two more models called Artist and Album. However, just as with views, we don’t want to be too granular when defining our models. In this case, we don’t have to separate artist and album information because the app doesn’t allow the user to select a specific song by a given artist. Instead, the data is organized by station, the song is the center point, and the artist and album are properties of the song. That means we’re able to combine the song, artist and album data into one model. This greatly simplifies the data side of our app. It also simplifies the API that we have to implement on the server-side because we don’t have to load individual artists or albums. To summarize, for this example, we’ll only have two models — Song and Station.
h4. Stores
Now that we’ve thought about the models our application will use, lets do the same for stores.
Figuring out the different stores you need is often relatively easy. A good strategy is to determine all the data bound components on the page. In this case, we have a list with all of the user’s favorite stations, a scroller with the recently played songs, and a search field that will display search results. Each of these views will need to be bound to stores.
h4. Controllers
There are several ways you can distribute the application’s responsibilities across your application’s controllers. Let’s start by thinking about the different controllers we need in this example.
Here we have two basic controllers — a SongController and a StationController. Ext JS 4 allows you to have one controller that can control several views at the same time. Our StationController will handle the logic for both creating new stations as well as loading the user’s favorite stations into the StationsList view. The SongController will take care of managing the SongInfo view and RecentSong store as well as the user’s actions of liking, disliking, pausing and skipping songs. Controllers can interact with each other by firing and listening for application events. While we could have created additional Controllers, one for managing playback and another for searching stations, I think we’ve found a good separation of responsibilities.
h3. Measure Twice, Cut Once
I hope that sharing our thoughts on the importance of planning your application architecture prior to writing code was helpful. We find that talking through the details of the application helps you to build a much more flexible and maintainable architecture.
Great read. Looking forward to getting my hands dirty now.
looking forward to try it out, thank you :)
This is very helpful. The MVC examples from the SDK are all pretty basic and aren’t always obvious how to get to the finished product from the beginning. Would love to see more of these posts breaking down best practices for the MVC pattern.
Great article, if we see the demos on the kitchensink application, there are many ways to structure the apps, i think is necessary an standard way to build sencha touch and extjs application, the mvc model is a good start and articles like this are a great contribution to all of us.
Thanks!
Is there an example of using “application level events” anywhere? I noticed an EventBus class, but litte documentation on how to use it… So far, I can only find how to handle component level events w/in a controller…. Thoughts? Or is it as generic as adding events to the application itself, and providing listeners at the application level? Thanks! Great write up!
Looking at structure is like CodeIgniter framework and other like that.
I see aplication like groupoffice who is build on Ext JS engine and have a problem to a dam small window to work on mobile phone.
Every on integrate multi platform framework/engine but how Ext JS do that? and i mean how it works this on android, iphone, mac, windows, linux platforms?
Nice structure but stays with a question; why or for what reason is the index.html placed under the Ext-4.0 directory ?
Lots of good points, but no code?
Great post. But I still miss the code. Maybe it could be available as a new MVC example?
Another thing is there are so many people still struggling how to build a MVC application with login page. At least how to organize it.
This post was purely meant to get you to think about the structure and architecture of your application before actually implementing it. That’s why there is no code discussed. In the next part of this series we will look at how to actually implement the things we discussed here.
Good post Tommy. I know you didn’t want to get into actual implementation code but could you elaborate on your statement, “Controllers can interact with each other by firing and listening for application events.”
Great article with good examples, thank you very much for refreshing my knowledge, looking forward to more such simple language articles. Cheers.
You’ve used very interesting screen shoots for illustration. Is there any way to look into sources of this application? Does it published already? It would be really helpful to explore it’s insides. :)
Hi, thanks for the nice post. One question though. Supose my app is quite large and i have many controllers and views. What approach should i take, load all controllers and views in my main app file or, can they be loaded on demand ? I would much appreciate some thoughts on this matter and i think many users are wondering about this.
I second Liviu M’s question. My app cannot possible load all the models, views and controllers upfront. Having a way to load modules (their MVC components) on demand would really help. I’m hacking my own way right now and would love to stick to Ext’s way rather than creating my own.
With the controllers declaring which views they’re associated with and listining to events from those views, what is the best way for an action (say a click) in one view to cause an effect (Say loading a record into a form) into another view ? I keep ending up passing my events up to the app it’s self and then calling controller methods.
@Liviu, @Juan, @AwesomeBob
Since the answer to either of those questions is not simple, I will answer them as part of my next article. I might release some sample code used in the next article before it is posted.
Another great example would be of how to use the tabpanel in an MVC arrangement. For those of us new to MVC, its not clear how the activation of different tabs can be moved out to the controller, when effectively that activity is tied into the tabpanel view. Also, should each tab be a different view? etc
Regards,
Andy
Thanks for the post, Tommy. Please keep the best practices articles coming!
To Andrew Peacock +1
Now I’m doing it by dispatching call in handling tab’s ‘activate’ handler, like this:
this.viewport.query(‘#whereami’).forEach(function(panel){
panel.on(‘activate’, function(){
Ext.dispatch({
controller: ‘whereami’,
action: ‘index’,
viewport: this
});
}, panel);
}, this);
It looks too complicated and I’m really interested in the “right way”.
Hi Andrew,
Thanks for your suggestion. Is Ext.Dispatch part of ExtJS 4? I can only find some references to GXT and Touch that refer to it.
Regards,
Andy
@AwesomeBob: From your controller, you can handle the event (say a grid’s selection model selectionchange event), use Ext.ComponentQuery to find the form you want to load the record into and then just call form.loadRecord. Did I misunderstand your question?
@Juan, I was expecting something a little more structured, such as a controller being able to call methods on another controller in order for the second controller to perform actions in its view rather than Controller A interacting with Controller B’s View. However I keep having difficulty deciding how best to have controllers aware of each other but still be decoupled. Maybe I’m just thinking about it too hard and creating a paradox for myself.
I think Andrew stumbled upon what I’m looking for with Ext.dispatch()
It is not easy!
In ExtJS3, I’ve used an event manager approach can be used to communicate between controllers. Is this recommended for also passing events between controllers?
Sorry, that should have said:
“In ExtJS3, I’ve used an event manager approach can be used to communicate between COMPONENTS. Is this recommended for also passing events between controllers (in an MVC approach)?”
Excellent article and i completely agree with points mentioned at the start that an application should be designed right from the start.
Tommy, Does ExtJs provide anything for MVP pattern? From your experience is MVP a good pattern to design applications using javascript?
Can we please have some code examples to solidify the concepts?
Also, where is the server side code meant to sit within your application? Are all third party libraries really meant to sit in the root… I just don’t think I’m following this correctly.
@Brad Those concepts are beyond the scope of this article and you really should know the answers to your questions before approaching building web application development. Hit up a school or do like most of the people the professionals clean up after and just buy a “… for Dummies” book.
Also check out the examples and the API documentation.
@AwesomeBob, I think your reply was unnecessarily crass. I have been developing web apps for some time now, but thanks anyway for the tip about “… for Dummies”… I’me sure it will come in handy one day.
The fact that server side work always seems to be beyond the scope of Sencha blog posts is a little bit frustrating when trying to build an actual web application using their tools and trying to follow their architectural ideologies. At the very least. some through explanation of how their build tools are designed to work with different designs would be nice.
By the way, in answer to your question, if you have a view with a button on it which needs to update a component in a different view, the controller for the button should trigger an event which the controller for the updated component should register.
Eg:
Button[Stop] -> Controller[MusicControls] -> Event[music.stop] -> Controller[SeekBar] -> Slider[Stop]
@Brad I didn’t mean to be too insensitive to your concerns. What server-side stack or technologies do you use? I use the LAMP stack (The P standing for PHP in my case) and have been using it for over 8 years now. I’ve been developing my own REST framework and the directory layout I plan on using for my next ExtJS 4 app will be laid out as follows:
ROOT ->
—- application/ (where the bulk of my PHP code resides)
——–includes/
————inc.basic.php (includes all other required included files)
————inc.constants.php (directory and application specific constants like)
————etc…
——–classes/ (Where my PHP classes go in name-spaced directories)
—-www/ (the document root of my app which is used for the www. subdomain)
—-js/ (JavaScript directory)
——–app/ (My JavaScript MVC root)
————controller/
————model/
————view/
————app.js
——–ext/ (ExtJS 4.0 source directory)
————bootstrap.js
————ext-all.js
————etc…
—-index.php (or index.html if your application is very simple and doesn’t require any PHP benefits, also includes my extjs files)
—-api/ (the document root of my api interface for my framework)
——–index.php (api specific index.php file which interfaces with my PHP framework to respond to ajax requests from my front-end web app, uses VirtualHosts fo that api.myapp.com would be used for ajax requests from http://www.myapp.com which is served from the www/ directory mentioned above)
Now to address your response to my query about the communication between controllers:
I asked what is the best way to communicate commands from one controller to another where the desired action is triggered as a result of an event from view a (associated with controller a) and the desired result is a change in view b (which I assume should be managed through controller b). Any one can use controller a to handle an event from view a, my request is how would I then perform actions through controller b to change view b?
@AwesomeBob
Yeah that’s a pretty nice application structure. My thoughts at the moment are how do you account for a hybrid application, one in which you still generate some HTML on the server (like is done by most blogs/cms’s) whilst still incorporating elements which use extjs.
To clarify my thinking:
ComponentA in ViewA triggers an event, which is listened to by ControllerA
ControllerA triggers an event (Let’s call it EventACTION).
ControllerB listens for eventACTION and makes a change to ComponentB in ViewB
And that’s my question, what is the best way to make Controller B listen to Controller A actions in ExtJS 4’s proposed MVC architecture? It should be best to develop the controllers decoupled from each other so should the Ext.application object act as the interface between controllers?
Was an interesting post with equaly interesting comments. When can we expect the follow up that promisses to answer all those interesting questions ?
@AwesomeBob Take a looke at Ext.app.Application.fireEvent
You can take an approach where as Controller B listens for an application event such as “PlayerStop” or “DownloadComplete” which the appropriate parameters.
What about testability? What about error handling?
Oh, wait, this is extjs. No one gives a rip about either of those things. Because they’re too busy building toy applications.
https://github.com/lucassus/extjs4-account-manager
Look at the above for a full CRUD/mvc example with code that works. It’s basic….and it looks like the guy just finished the unfinished non-working example from the API docs…..but it works……..
I’ve been trying to adapt his pattern to a dual-grid example where a child grid loads records based on parent record chosen in parent grid.
Wish there were more examples out there.