Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

Robust MVC

4.76/5 (15 votes)
6 Oct 2012CPOL6 min read 48.2K   2K  
Robust MVC framework for desktop and web development

Introduction

In development of a sizable software product there are a number of aspects to consider: overall architecture, physical layout, object lifetime management, maintainability, performance, design (anti-)patterns and the list goes on. Development can start from a clean slate and add all the above aspects one by one or start of with a template that addresses some of these items. But, alas such template does not exist and the ones that are available tend to focus on one of two of these aspects and take shortcuts in the others.

In this article we will explorer a more complete example and provide a more robust framework that can be adapted to meet further needs.

Real world

Most discussions for creating and application start of with musing about Model-View-Controller [MF], but most native application projects still start of from MFC template that has a Document-View "architecture". Things tend to move downhill from there and after a while business logic is intertwined with presentation and physical layout is intertwined with MFC. Sprinkle couple more external libraries and you've got a big monolithic code base with ever increasing build times and requiring more and more heroic effort to resolve issues or introduce new functionality. Side note, a managed application templates are not much better, but check out my other article on managed application/WCF [wcf technobabble].

Robust Model-View-Controller

A few innovations were identified to improve upon the Model-View-Controller [MVVM, MVP], but it seems much more important to improve the way MVC is integrated with the platform/library used the build the application. More over, application today are rarely involve just one platform, some parts run on desktop and some are executed on the backed (or on one of its tiers). So the integration approach shall allow to reuse the actual model and controller implementation across several platforms. Implementation for view(s) are generally more dependent on the presentation/look-n-feel/visualization technology so trying to get the same implementation for the presentation logic is generally not worth the effort. But with model/controller logic out of the way, it becomes much more straightforward to re-implement the view (but see below how simplify that task by re-using visualization building blocks) for the appropriate platform.

The scope

So let's define the scope that would be covered in this example. Reminder, we want to cover something reasonably complex, as to not skip important aspects. Let's do something graphical, something using OpenGL, better yet lets use something a bit more recent -- shaders. Usually applications are not build from scratch, so let's use some external libraries and see how that fits in: Boost is a popular one, as well as GLEW to help out with OpenGL. How about maintainability and physical layout: establish separate modules for corresponding functionality and allow to build unit tests as well allow reuse in other projects.

Now let's pick the actual platform and actually define parts that will be platform independent. Model and Controller shall be platform independent. The rendering of views will be OpenGL and as it is cross platform, we'll keep the rendering part cross platform as well.

Now the application itself -- the glue that initializes and binds everything together (note, it's binding, not much else). We will actually setup two of these: one will use MFC while the other will be a standalone http webserver. Why to choose MFC, because you most likely already know the good and pain points about it. Why target a stand alone webserver, obviously because web connected frameworks extremely useful. But also because it is diametrically opposite of a desktop MFC application, so that should show robustness of the approach.

To top it off, documentation shall be generated automatically and (if we get time) source code analysis and code coverage.

Preview

Sometimes it's better to start off with desert, in this case let's look at snapshots:

Image 1 Image 2
Application using OpenGL shaders Webserver and Chrome browser

Below is a screen cast using the web server. Note, the radius is increased/decreased until specified limits are reacheds. The limits are enforced by the controller.

Integration

Below is a snapshot of desktop integration, with corresponding areas highlighted. Note the following key area:

  • The Model and Controller have no dependencies on the gluing coded (MFC).
  • The gluing code has minimal dependencies on the Model, Controller.
  • Modification to the model can only be performed by Controller (i.e. the model can be retrieved from document only as const).
  • The view class only deals with initialization of the graphic pipeline and delegates the rest of rending to the ModelRender class.

Image 3

The two diagrams below physical layout of the project, with following areas of interest:

  • The Model and Controller have no dependencies on the gluing code. This point is similar to one in prior section, but on physical structure level.
  • The Model and Controller have not dependencies on the viewing code.
  • In the gluing code the Document has no dependencies on the graphic api (OpenGL) used for visualization

Image 4

Image 5

Graphcs

The example in this article targets OpenGL 2.1 and GLSL 1.20 shaders. The selection for this version of OpenGL/GLSL is mainly to ensure it can be executed on the "run of the mill" hardware (and actually this will run on bare bones Intel embeded graphics, which is common in today's laptops). At the same time, this will cover following important aspects:

  • OpenGL context initialization
  • Usage of GLSL shaders with uniforms' values based on the model
  • Multiple views sharing the same OpenGL context
  • OpenGL context teardown when all the views are closed
  • Separate context for each document/model to enforce consistency

The drawing effectively is a quad drawn using OpenGL's fixed pipeline, and then a second quad clipped by radius of value specified in the model. The clipping is done using GLSL shader, which is kept pretty simple:

GLchar* vSource = 
    "varying float x;                                                               \r"
    "varying float y;                                                               \r"
    "void main() {                                                                  \r"
    "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;                     \r"
    "   gl_FrontColor = gl_Vertex;                                                  \r"
    "   x = gl_Vertex.x;                                                            \r"
    "   y = gl_Vertex.y;                                                            \r"
    "}                                                                              \r"
;

GLchar* fSource = 
    "uniform float radius;                                                          \r"
    "varying float x;                                                               \r"
    "varying float y;                                                               \r"
    "void main()                                                                    \r"
    "{                                                                              \r"
    "    float r = sqrt(x*x + y*y);                                                 \r"
    "    if( r <= radius ) {                                                        \r"
    "        gl_FragColor = gl_Color;                                               \r"
    "    } else  {                                                                  \r"
    "        gl_FragColor = vec4(0.01, 0.01, 0.01, 1);                              \r"
    "   }                                                                           \r"
    "}                                                                              \r"
; 

Unit Test and Test coverage

This section shows snapshots for unit test reports as well as coverage attained with the unit tests: Image 6

Image 7

Installation

And in conclusion to the best part: all of the above can be reasonably reused though a new Visual Studio Wizard. To install you can navigate to the Visual Studio Gallery, use Visual Studio as shown below or download installer at the top:

Open the new project dialog in Visual Studio. Type in the search term: "igor okulist". Select the "Robust MVC" item, and proceed installation. If everything works, you should see a dialog as the one shown below: Image 8

After the installation the new project dialog will have new Wizard category: Image 9

Summary

The article presents key points on implementing and integrating Model-View-Controller framework into existing application development framework. The approach maintains minimal dependencies and facilitates cross platform development. Additionally the same Model-View-Controller implementation is integrated with a web server that allows to the same model [rendering] through a web browser.

FAQ

  • Q: Where is the source?!
  • A: Still being prepared. Bookmark, vote or post comments to help me prioritize vs my other hobby projects. By the way contact me if you have experience with making C++ Wizards for Visual Studio 2010. Download the wizard installer and start making new projects based on this framework!

See also

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)