A Case study on MFC

The Microsoft Foundation Class Library is an application framework for programming in Microsoft Windows. Written in C++, MFC provides much of the code necessary for managing windows, menus, and dialog boxes; performing basic input/output; storing collections of data objects; and so on.

The MFC framework is a powerful approach but using it
impacts the design of the application, it's very intrusive and we have to be careful of how we use it. Let's analyze MFC8 with CppDepend to discover its code quality and design.

CppDepend is a tool that simplifies managing a complex C++ code base. Architects and developers can analyze code structure, specify design rules, and plan massive refactoring, do effective code reviews and master evolution by comparing different versions of the code.
CppDepend supports the Code Query Language (CQL) for maximum flexibility.

Basically CppDepend considers your code as a database and you can write some CQL statements to query and check some assertions on this database. As a consequence, CQL is similar to SQL and supports the SELECT TOP FROM WHERE ORDER BY pattern.


With CppDepend we analyze the quality of implementation and also the design of MFC.
A quality of implementation is important for developer who debug inside MFC,indeed not all things work as we like and sometimes we have to look inside the library code so if it's not well implemented it complicate the task when debugging. A design of MFC is very important for developers because it impact the design of the application because it's very intrusive.

MFC General Information's:

The dependency Graph shows that MFC uses 149 methods from ATL and 1014 from Windows API, and there's general Information's about MFC:

Code Implementation:

Naming Rules:

 Let's execute the following CQL request:

 WARN IF Count > 0 IN SELECT FIELDS WHERE !NameLike "^m_" AND !IsGlobal
The blue squares represent the result of the query, so almost 50% fields don't begin with m_".


And what about methods naming:
WARN IF Count > 0 IN SELECT METHODS WHERE !NameLike "^[A-Z]" AND !(IsClassConstructor OR IsConstructor) AND !IsInTierProject AND !IsGlobal AND !NameLike "^~" AND !NameLike "^operator"


There are just some few methods that not begin with Upper case.

 

Cyclomatic Complexity:

Cyclomatic complexity is a popular procedural software metric equal to the number of decisions that can be taken in a procedure.
We can also consider that a method is complex if NbLinesOfCode,NbParameters or NbBariables are great than a defined values.

SELECT METHODS WHERE (NbLinesOfCode > 100 OR CyclomaticComplexity > 20 OR NbParameters > 5 OR NbVariables > 8 )

So 706 methods are candidates to refactoring, but the request can be changed, it's depending on the choice of the complexity criteria for each team.

Comments:

SELECT METHODS WHERE NbLinesOfComment > 0

Almost all classes are commented so developers can have an idea of what a method does particularly when debugging inside MFC.
Let's see if all complex methods are commented.
SELECT METHODS WHERE (NbLinesOfCode > 100 OR CyclomaticComplexity > 20 OR NbParameters > 5 OR NbVariables > 8 ) AND NbLinesOfComment ==0 


There are just few complex methods not commented.

Design:

No existence of namespaces:

The namespace is an important concept to design application, it isolates functionalities under a module and provides a logical grouping, it can also make a library simple to use. Unfortunately MFC don't contain any namespace in spite of the existence of different functionality (GUI, OLE, Database, Containers ...).

Global functions and variables:

 MFC contains 786 global functions and 338 global variables, its lot for an object oriented framework.

Inheritance:

SELECT TYPES WHERE NbBaseClass >0

Almost all class has at least one base class, it cause a high coupling between classes.

Types Cohesion:

The single responsibility principle states that a class should have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class. There are several LCOM metrics. The LCOM takes its values in the range [0-1]. The LCOMHS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. Note that the LCOMHS metric is often considered as more efficient to detect non-cohesive types. LCOMHS value higher than 1 should be considered alarming.

 WARN IF Count > 0 IN SELECT TYPES WHERE LCOMHS > 0.95 AND NbFields > 10 AND NbMethods >10 AND !IsGlobal ORDER BY LCOMHS DESC

31 types from 529 are considered non cohesive.

Dependency between Classes:

The option Direct & Indirect Weight of use the Dependency Structure Matrix is the perfect tool to let users know where the code structure is tangled with dependencies cycles.

The screenshot below showsthat the 2 classes CDocument and CCmdUI are involved in a cycle of minimum length 5.

The whole dependency matrix shows that almost all MFC types are coupled directly or indirectly.

Coupling:

The efferent coupling for a particular type is the number of types it directly depends on. Types with high efferent coupling are more complex than others,CppDepend propose a search panel, it's like a wizard that help you construct query easily.
Let's search for Types where efferent coupling is more than 30.

 Doc/View Concept:

MFC separates data management into these two classes. The document stores the data and manages printing the data and coordinates updating multiple views of the data. The view displays the data and manages user interaction with it, including selection and editing.

 In dependency graph CDocument and CView are mutually dependant and usually the model don't have to know the View and it must be independent of any external framework.


The model has to be as simple as possible with simple types and without any unnecessary coupling.
The following CQL request demonstrate that CDocument is highly coupled with GUI classes:
SELECT TYPES WHERE IsDirectlyUsedBy "CDocument"

The goal is to reuse the same model in different projects (Console, Gui, WebService, ...) and if our model is the CDocument we can't reuse easily in other projects.

Recommendation:

Never use CDocument as model but use it just as controller to refresh views.

 
MFC Automation Server :
CDocument can be used also as COM Component, but CDocument is coupled with CView and using CDocument as COM component can occur some unexpected limitations and problems. When we instantiate a CDocument as COM Component a handle of view is created due to the coupling Doc/View so the number of instances to create is limited by the number of window handles that can be created, and the problem occur particularly if the instances are created in a no desktop session, in this case the number of handle that can be created is very limited by default.

Recommendation:
Avoid using CDocument as COM component, keep it simple and use ATL instead it's more simple and flexible.

Use or don't use MFC?

MFC is well implemented but not really object oriented and the classes are high coupled, so be careful when using it and avoid any unnecessary coupling,for example prefer using ATL for COM component and STL for containers.

It's preferable to avoid as possible the coupling of your model with Doc/View concept, it make your design less flexible and add more complexity.

The goal is to spend more time in developing the business layer and isolate any technical layer will be very advantageous:

 

  • Human resources department don't need to spend a lot of time to search for MFC gurus; maybe just few MFC developers will be sufficient.
  •  

  • Developers don't add a compleB7 Developers don't add a complexity of a framework to the complexity of what's they implement.
  •  

  • Reusing easily the business layer in other context (Web Services, Console, ...).
  • So keep it simple and isolate the impact of any technical framework used, for that be careful for any unnecessary coupling.



    About the Author

    Issam Lahlali

    Product Manager of CppDepend. MCSD and MCSD.net certified.

    Comments

    • A case study in weakly drawn conclusions

      Posted by mikeblas on 06/26/2009 11:14am

      The title of this article claims its a "case study". I'd expect that it studies one particular case of implenmentation of an application that was implemented using MFC, rather than the static analysis of the library using some artibrary metrics. The introduction to this article then claims to offer an investigation of the "quality of implemention" but just cites some statistics without explaining their real meaning. I'm not sure that really leads to any insight into MFC's design, particularly when there's so little analysis of the context. The author claims that MFC contains 786 global functions and 338 global variables--and says that's a lot for an object-oriented framework. But he fails to consider the size of the library. It might be a lot for a small framework, but for a framework that's as large and comprehensive as MFC is, I'm not sure it's a problem. The author also appears to ignore the exposure of those globals in his analysis. If they're present inside the implementation and not exposed as a part of the library's interface, is there really any concern for their presence? Some of the conclusions made aren't realistic. Namespaces are nice, but they're not really as beneficial as the author claims. When making a suggestion about MFC -- such as advising that it should use namespaces -- one must take into accout the billions (trillions?) of lines of existing code that MFC customers have in place. Unconditionally adding namespaces to the library would break them all. Conditionally adding namespaces adds to the complexity of the library, both for the development team (testing, documenting) and the consumer (are namespaces on? or not? For some of my project, none of it, or all of it?). In light of these costs, such a change really isn't worthwhile. I'm afraid I can't understand how the author possibly concludes that "if our model is CDocument we can't reuse easily in other project" just because CDocument's implementation has some number of other dependencies on other classes in the same library that implements CDocument.

      • C++ is not dead

        Posted by Issam_Lahlali on 06/26/2009 04:19pm

        i'm agree with you, c++ is very simple and is not dead, but the question is: Why more companies choose dotnet or java to develop new projects instead of C++? in my opinion because C++ developers think low level and spend more time in technical layer and the frameworks play this role. C++ is very similar to java or C# but unfortunately you can't find an easy framework. C++ is not dead but we have to focus more in design to avoid coupling and particulary with technical framework.

        Reply
      • Already

        Posted by mikeblas on 06/26/2009 12:49pm

        What makes you believe that it's not already as simple as possible -- or at least, nearly so?

        Reply
      • Keep it simple

        Posted by Issam_Lahlali on 06/26/2009 12:03pm

        The title was "Inside MFC" but it was renamed by codeguru staff , and other articles will be posted to discuss the MFC library at http://cppdepend.blogspot.com/, I can't talk about MFC in one article. The problem with C++ is all the time we found an explanation for a complex design or implementation, for example for namespaces it's very useful when we use any framework, in my case when I use C# I know that all Gui classes are in Sytem.Windows and easily I can found the class concerned but with MFC all the classes are in the same package and if I forget the name of a class I spend more time to found it, it can appear stupid as explanation but it's very useful for developer. And for CDocument , unfortunately the C++ community ignore design of an application, the rule is simple : the model must be as simple as possible just POCO objects are sufficient all the time. I worked in many migration projects and all the time we spend a lot of time to dissociate the model from framework used, so why add unnecessary coupling to your model, CDocument can be used as controller to refresh. My rule is Keep it Simple for anyone (architect,designer,developer) and try as possible avoid high coupling , I explain briefly the interest of that in this article http://cppdepend.blogspot.com/2009/06/keep-it-simple-concept-make-c-much.html.

        Reply
      Reply
    Leave a Comment
    • Your email address will not be published. All fields are required.

    Top White Papers and Webcasts

    • 10 Rules that Make or Break Enterprise App Development Projects In today's app-driven world, application development is a top priority. Even so, 68% of enterprise application delivery projects fail. Designing and building applications that pay for themselves and adapt to future needs is incredibly difficult. Executing one successful project is lucky, but making it a repeatable process and strategic advantage? That's where the money is. With help from our most experienced project leads and software engineers, …

    • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

    Most Popular Programming Stories

    More for Developers

    Latest Developer Headlines

    RSS Feeds