Sunday, October 3, 2010

Replace MVVM with AbstractView pattern

With MVVM pattern, sometimes, people run into the problem that the VM class soon explodes to the size of a few thousand lines of code. To solve this problem, I'll present a new pattern I call Abstract View.

The reason for VM class to explode in size is that it is carrying too much responsibility.
1. Provide binding properties
2. Provide binding commands
3. Provide implementaion for commands and other functions required by the View and its code behind.

For a complicated view, it won't take long for the view model class to reach unmanagable size. To solve this problem we need to delegate some of the functions to other classes. But the View class still requires a binding target. Instead of using a View Model class, I'll call this simplified view model class Abstract View in that it defines the possible properties and operations a concrete view that is bound to it may carry out hence define the view in an abstract manner.

Here is a static view of this new pattern.



By using more than one CommandProviders, you can separate concerns horizontally and by allowing CommandProviders to user other delegates, you can separate concerns vertically. Mediators become facades for various delegated function units each providing service of a subject area.

This is a sequence diagram for starting up.



A typical user edit action sequence.



A typical user command handling.



Close view.



In this pattern, most of the functionality is moved out of the "ViewModel" class therefore it's size will be under control. When the Mediator size is grown out of control, it may optionlly use other delegates to redistribute its functionality.

Wednesday, July 14, 2010

Understand Model-View-Controller (MVC)

Among all the design patterns, MVC is probably the most cited. It had become such a legendary that part of it has been mystified. Wiki page for it even claims it "is a software architecture, currently considered an architectural pattern".

The following are some excerpts from the earliest description of MVC.

"In the MVC paradigm the user input, the modeling of the external world, and the visual feedback to the user are explicitly separated and handled by three types of object, each specialized for its task. The view manages the graphical and/or textual output to the portion of the bitmapped display that is allocated to its application. The controller interprets the mouse and keyboard inputs from the user, commanding the model and/or the view to change as appropriate. Finally, the model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller). " [SB]

"Unlike the model, which may be loosely connected to multiple MVC triads, Each view is associated with a unique controller and vice versa. Instance variables in each maintain this tight coupling. " [SB]

"Models are those components of the system application that actually do the work (simulation of the application domain). They are kept quite distinct from views, which display aspects of the models. Controllers are used to send messages to the model, and provide the interface between the model with its associated views and the interactive user interface devices (e.g., keyboard, mouse). Each view may be thought of as being closely associated with a controller, each having exactly one model, but a model may have many view/controller pairs." [KP]

"To maximize data encapsulation and thus code reusability, views and controllers need to know about their model explicitly, but models should not know about their views and controllers." [KP]

"Every instance of a view has exactly one model and exactly one controller. The model is normally set explicitly. Because view and controller classes are often designed in consort, a view's controller is often simply initialized to an instance of the corresponding controller class." [KP]

If we put all these together, the following class diagram is a good description of this pattern in its static view.



The following sequence diagrams show this pattern in action.
Initialization:


User Interaction Handling example:


Release:


The main benefit of this pattern is "This three-way division of an application entails separating (1) the parts that represent the model of the underlying application domain from (2) the way the model is presented to the user and from (3) the way the user interacts with it." [KP]

This pattern was designed in the environment of SmallTalk-80. Clearly, it had achieved what it is intended for.

However, when apply it to different development environment, adaption is often necessary. The biggest difference in most popular development environments versus SmallTalk is probably the fact that most of the them have GUI support frameworks, MFC/C#/VB/Java on Windows platform and Java/Cocoa on Mac. Most of these GUI support frameworks provides a set of "Controls" with built-in keyboard and/or mouse handling capability. It seems the "Controller" is now mostly merged into "Views" in these frameworks. The spirit of MVC is the separation of concerns. Despite the changes in development environment, the need for separation of concerns has never been altered. "Controller" in the form of its classic definition may not be required anymore but there is still the need for a class to control the transition of user device (keyborad and mouse) control, to interpret user guestures into business actions, to control model persistence. In this sense, MVC is still a valuable pattern for any GUI design project.

[SB] Steve Burbeck, "How to use Model-View-Controller (MVC)", 1987

[KP] Glenn E. Krasner and Stephen T. Pope "A Description of the Model-View-Controller User Interface Paradigm", 1988

Thursday, April 15, 2010

Agile and Design Evoluation

Agile is right in at least one way in that no matter how hard you try, your requirements do change over time. There are good reasons for requirements to change. Market condition changes, technology advances, and product scope changes are all good reasons for it.

Let's admit that requirements are changing and you are always shooting at a moving target. To handle requirements effectively, you need a good strategy to evolve your design to deal with the changes.

In agile practice, developers are often given a limited view of the product to start their implementation. The best design they can come up with will unavoidably only cover the variations within that scope. You may blame the initial designers for lack of abstraction in their design to handle future variations. But in reality there is nothing wrong with it since they are limited by the knowledge about future requirements. It is hard, if ever possible, to determine how abstract their design should be to cover possible future variations without knowing what will come up. A more practical solution is to evolve your design from concrete to more abstract.

One way of handling requirement changes is to constantly revisit your conceptual models in your design in every iteration of your agile process. Before you add more if-else statements to your functions, more enum values to your switch statements, or boolean flags to your data structures, you should really think about your conceptual models and your state machines. Are they still valid given the new requirements?

If-else statements are really behaviour changes. Theoretically, behaviour changes are supposed to be handled by polymorphism in good OO design. The need for more if-else statements is a good indication that you need more derivations to handle behaviour differences. More of your base classes should become abstract (pure virtual in C++). If-else statements may bandage your obsolete design but will lead to more grief for the future.

More enum values or boolean flags are really amendments to your existing state machines, exponentially unfortunately. As state space of your state machines expands so dramatically, it is unlikely your last state diagram will hold. Revisit these state diagrams to see how it should really be under the new requirements.

Given a set of requirements, come up with a good OO design is already a challenging task in most cases. Shooting a moving target only makes it harder. Without a good strategy to deal with requirement changes, it is unlikely your software project will end up with great success, at least from software design's perspective.

Wednesday, March 24, 2010

Agile: What it should be and what it should NOT be

Agile as a software engineering pratice is gaining popularity. However, it doesn't always meet people's expectation. Like everything else, it comes with Pros and Cons.

When it all comes down to it, what Agile is trying to against is so-called "overhead" in "traditinoal waterfall" software engineering approach. We may want to take a closer look at the "overhead". In traditional waterfall approach, we may have documentations for requirements and analysis, design at different levels, and code. What is considered "overhead" is the time spent to create and maintain these documents. This is clearly marked by the advocates for "face-to-face" communication in Agile. However, there exists certain documentations that are required throughout your project that worths the effort to maintain. An obvious example is architectural design and component design guidelines. Theoretically, the information in these documents can be communicated by "face-to-face" communication but in reality that is not the efficient way to communicate them in entirety. How can you talk about your architectural design precisely the same for many times? Development teams are often very dynamic. If you want your team to have a consistent understading of the architectural design, documentation is more than likely a more efficient way of communcation than face-to-face. Without architectural design documentation and component design guidelines, the pressure exercised by Agile approach often lead to broken architectural integrity and sometimes broken encapsulations at lower level. When the skill level of the developers differ, the problem can eaily spread through the enire code base. The consequence is not obvious in current and near future itertions. However, as they accumulate, your code base becomes harder and harder to maintain. The cost to add new features will increase. For Agile to be efficient, it should be guided by architectural design and component design guidelines.

The good side of Agile is to advocate "Test-Driven-Development". This is what it should be. If a project is started with a good architecture design and good test coverage, it is unlikely for broken architectural integrity to happen. Component design guidelines may be reflected in the design and implementation of test suites.

Like anything else, Agile may be abused as well. It is just like a knife. You may cut your fruit or your finger depending on how you exercise it.

Agile should NOT be used as an excuse for lack of long term vision of product management. Agile advocates "embracing changes". However, it does not warrant product management the freedom to change their mind at free will often as a result of the lack of vision. In software development, changes are costly regardless what software engineering approach you take. You waste the time to put the code in and the time to remove unused code less to say the test code that comes with it.

Agile should NOT be used against the pursuit of a relatively stable architecture. Among all the costly changes, architectural change is probably the most costly. Without architectural design and component design guidelines, your code base is unlikely to be designed for changes since developers are rushing to finish current sprint without any consideration for things outside current sprint. Without architectural design and component design guidelines, you do not have the right tool to really embrace changes. That is exactly against what Agile has advocated in the first place.

For Agile to be sucessful, you really need to be agile. Learn from the lessons in your pratice and make changes as mistakes or negative effects are observed. That is the real spirit of the word "agile". Religious belief is just the opposite of it.