MFC (Microsoft Foundation Class)

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.

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 CQLinq 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 shows that 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 dependent 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 CQLinq 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.

Irrlicht

Irrlicht is a 3D engine library that use many GRASP concepts, let’s discover with CppDepend the benefits of using this kind of patterns, and to show using of GRASP concepts we will focus on the namespace irr::gui.

GRASP Patterns

Creator

To detect with CppDepend the existence of creator, the easy way is to use a CQLinq query like this:

SELECT METHODS WHERE DepthOfCreateA “irr.gui.CGUISkin” == 1

So the CGUIEnvironement is the only class that create CGUISkin, but what about other GUI elements?
almost all GUIElement are created by CGUIEnvironement class except CGUIButton

SELECT METHODS WHERE DepthOfCreateA “irr.gui.CGUIButton” == 1

As we observe the CGUIButton is created in three different places, maybe there’s a reason for this behavior.
So the CGUIEnvironement class act as creator, but what’s the role of CDefaultGUIElementFactory class?
The dependency graph between CDefaultGUIElementFactory and CGUIEnvironement shows the relation between them:

Adding GUIElement begin with the invocation of CDefaultGUIElementFactory::addGuiElement , and this method invoke the right creation method from CGUIEnvironement, it depends of the type of element to create.
Finally the creation responsability and logic for GUI elements is isolated in two classes.

Controler

The Controler for GUIElements must at least manage event processing,this task is processed by CGuiEnvironement::OnEvent.
Let’s see which methods are used by OnEvent

SELECT METHODS WHERE IsUsedBy “irr.gui.CGUIEnvironment.OnEvent(constSEvent&)

So the event fired is processed by a class that implement IEventReceiver.

Which classes implement this abstract class?

SELECT TYPES WHERE DeriveFrom “irr.IEventReceiverORDER BY DepthOfDeriveFrom

What’s the other responsabilities of CGUIEnvironement?

As we have seen before this class create the concrete classes and also manage event processing, and to discover if it do another responsability we can search for methods used by this class:

SELECT METHODS WHERE IsDirectlyUsedBy “irr.gui.CGUIEnvironment

This class use also classes from irr::io namespace to persist and load into xml files , so maybe this class has many responsabilities and it can impact it’s cohesion, but it still tolerable because this class has all informations needed to persist data so this class follows the “Information Expert” principle of GRASP.

Low Coupling

Low coupling is desirable because a change in one area of an application will require less changes throughout the entire application. In the long run, this could alleviate a lot of time, effort, and cost associated with modifying and adding new features to an application.

Using abstract classes can improve the low coupling and we can evaluate the abstractness of a defined module by the following metric:


A = Na / Nc

Where:
* A = abstractness of a modulke Zero is a completely concrete module. One is a completely abstract module.
* Na = number of abstract classes in the module.
* Nc = number of concrete classes in the module.

The abstractness of Irrlich is equal to 0.1245972, and it contains 125 abstract classes.
And for irr::gui namespaces there’s 28 abstract classes , for each GUI element there’s the equivalent interface.

SELECT TYPES FROM NAMESPACESirr.guiWHERE IsAbstract

CppDepend provide DSM graph, and we can triangularize this matrix to focus under red borders highly dependent classes, and to detect modules.

As we can observe all abstract classes are grouped, so we can consider them as module, so we can isolated them in another namespace or maybe in another project.
And to see the benefit of using abstract class to improve the low coupling, let’s search for classes that use the concrete class CGUISkin.

SELECT METHODS WHERE IsDirectlyUsing “irr.gui.CGUISkin

Only one class know this class, it’s his creator.
And what about IGUISkin:

SELECT METHODS WHERE IsDirectlyUsing “irr.gui.CGUISkin

Unlike CGUISkin the IGUISkin class is visible and used by many classes.
What about coupling between namespaces:

A dependency cycle exist between namespaces, having this dependency can be not problematic but avoiding it enforce loose coupling, but what’s interesting than this dependency cycle is the manner that namespaces interact with each others.
When we choose to work with abstract classes, it’s recommended to interact between functional namespaces using abstract classes rather than concrete classes, except for namespaces that contains utility classes like irr::core.

Is Irrlich follow this rule?
For that let’s see what the namespace irr use as classes and methods.

SELECT METHODS WHERE IsDirectlyUsedBy “irr

As we can see almost all interaction with other namespaces pass by abstract classes, except for irr::video::CVideoModelList and irr::scene::CMeshBuffer.

Let’s discover the origin of the dependency with irr::video::CVideoModelList, for that we can execute the following CQLinq query:

SELECT METHODS OUT OF TYPESirr.video.CVideoModeListWHERE IsUsing “irr.video.CVideoModeList

so the class irr::CIrrDeviceWin32 use it because this class declare a field as video::CVideoModeList instead of video::IVideoModeList.

High 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.

SELECT TYPES WHERE LCOMHS > 0.95 AND NbFields > 10 AND NbMethods >10 AND !IsGlobal ORDER BY LCOMHS DESC

Only few classes are considered as no cohesive.

Conclusion

Irrlicht use namespaces to modularize the code base and absract classes to improve low coupling, so it makes it very easy to understand and maintain.
It’s a good example to follow if you want to improve your design quality.

OGRE3D internal design

OGRE (Object-Oriented Graphics Rendering Engine) is a scene-oriented, flexible 3D rendering engine written in C++ designed to make it easier and intuitive for developers to produce applications utilising hardware-accelerated 3D graphics. The class library abstracts the details of using the underlying system libraries like Direct3D and OpenGL and provides an interface based on world objects and other high level classes.

Let’s analyze analyze it with CppDepend to discover its design advantages.

OGRE3D Architecture

The following dependency graph shows the dependencies between the OGRE3D projects:

As we can observe the architecture is based on the plugin concept, its very useful to extend Ogre3D without any changes to the kernel project OgreMain which  provides needed classes to use for a plugin, for example we can see which classes of OgreMain are used by RenderSystem_GL plugin. For that we can execute the following CQLinq request:

SELECT TYPES WHERE IsDirectlyUsedBy “RenderSystem_GL

For a plugin it’s also very useful to know which abstract classes are used by it, it give us an idea about the contracts implemented or used by the plugin.

SELECT TYPES WHERE IsDirectlyUsedBy “RenderSystem_GLAND IsAbstract

Which paradigm is mostly used?

Lets search for global functions to discover if Ogre3d is Procedural oriented?

SELECT METHODS FROM PROJECTS “OgreMain” WHERE IsGlobal AND !NameLike “^operator

How about generic paradigm:

SELECT TYPES WHERE IsTemplate

Only few classes are templated so Ogre3d is mostly object oriented.

Inheritance

Using object oriented approach can implies an overuse of inheritance to exploit polymorphism concept.

Specially for OgreMain that represent the kernel of Ogre3d framework, where many classes are designed to be overloaded by plugin projects.

SELECT TYPES FROM PROJECTS “OgreMainWHERE NbBaseClass >0

But multiple inheritance increase complexity ,and we have to use it carefully.

Let’s search for class with many base classes.

 

Only few classes derived from more than one class.

Abstractness

For a plugin oriented architecture, the host must have many abstract classes to be more flexible and extensible.

Lets search for abstract classes of OgreMain:

SELECT TYPES FROM PROJECTS “OgreMainWHERE IsAbstract

Namespaces layering

CppDepend provides DSM graph, and we can triangularize this matrix to focus under red borders highly dependency cycle.

A dependency cycle exist between Ogre,Ogre::EmitterCommands and Ogre::OverlayElementCommands, having this dependency can be not problematic but avoiding this kind of dependency enforce loose coupling,this interesting post explain the benefit of layering.

Let’s search for the origin of dependency between Ogre and two other namespaces.

SELECT TYPES WHERE IsDirectlyUsedBy “Ogre

The namespace Ogre use all Cmd classes from the other namespaces, and all those classes are used by Ogre::ParticleEmitter as static fields, ParticleEmitter add them to CmdParam dictionary.

Maybe its possible to do it differently to avoid this dependency cycle but its not very problematic.

Type 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.

SELECT TYPES WHERE LCOMHS > 0.95 AND NbFields > 10 AND NbMethods >10 AND !IsGlobal

Only few classes are considered as no cohesive.

Design patterns used

Singleton

To ensure a class has only one instance, the better way is to use singleton pattern.

Lets search which classes are singleton:


SELECT TYPES WHERE
DeriveFrom “Ogre.Singleton

As we can observe that almost all manager classes are singleton,in general a manager is a good candidate to be singleton. And we can search for manager classes that not derived from Singleton

SELECT TYPES WHERE !DeriveFrom “Ogre.SingletonAND NameLike “Manager$

Only few managers not derived from Singleton, its normal because those classes can be instantiated many times.

Factory

The factory pattern is very useful to abstract the creation of objects,it enforce low couplig and high cohesion as explained in this post.

but having factory not implies that an instance is created by this factory, because we can instantiate the class directly, and we have to define a rule to be sure that the factory is used for instantiation.

For example about Entity class we can define the following rule to discover each class instantiate it:

SELECT METHODS WHERE DepthOfCreateA “Ogre.Entity” == 1

As we can observe only EntityFactory instantiate the Entity class.

Manager

Manager classe give access to a subsystem, is very useful to modularise the project, and Ogre3d contains many managers, each one represent a different subsystem.


SELECT TYPES WHERE
NameLike “Manager$

Facade

Facade defines a higher-level interface that makes the subsystem easier to use, and we can detect facade for your project by using Efferent Coupling metric. The Efferent Coupling for a particular type is the number of types it directly depends on. Types where TypeCe > 50 are types that depends on too many other types. They are complex and have more than one responsability. They are good candidate for refactoring.

But sometimes in the case of facade, having a high TypeCe can be normal.

Lets search for classes with high TypeCe:

SELECT TYPES ORDER BY TypeCe DESC

Not all of those classes are facade and for each class of them we can maybe find an explanation why TypeCe is high, and maybe some classes can be refactored, and i confess that i don’t master Ogre3d to explain that.

And the facade mostly used is Root class, let’s see what subsystem this class use.

As we can observe Root class use almost all manager classes.

And we can search for manager not accessible by Root by this following CQLinq query:

SELECT TYPES WHERE !IsDirectlyUsedBy “Ogre.RootAND NameLike “Manager$AND !IsAbstract

Observer

The observer is a pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement event handling systems.

Ogre3d use Listener classes to implement the observer pattern.

Let’s search for Listener classes for OgreMain project.

SELECT TYPES FROM PROJECTS “OgreMainWHERE NameLike “Listener$

Conclusion

Ogre3d is very clean as library, very well designed and very well commented.You can easily understand the utility of design patterns used, and its modularity can help you to accelerate the time of learning its capabilities.

Why POCO is well implementd and designed?

The POCO C++ Libraries are a collection of open source class libraries for developing network-centric, portable applications in C++.

POCO stands for POrtable COmponents. The libraries cover functionality such as threads, thread synchronization, file system access, streams, shared libraries and class loading, sockets and network protocols (HTTP, FTP, SMTP, etc.), and include an HTTP server, as well as an XML parser with SAX2 and DOM interfaces and SQL database access.

The modular and efficient design and implementation makes the POCO C++ Libraries well suited for embedded development.

Let’s take a look inside POCO using CppDepend and discover some facts about its implementation and design.

POCO Implementation

Number of line of code

Methods with many number of line of code are not easy to maintain and understand, let’s search for methods with more than 60 lines.

Less than 1% of methods has more than 60 lines.

Cyclomatic Complexity

Cyclomatic complexity is a popular procedural software metric equal to the number of decisions that can be taken in a procedure.

Let’s execute the following CQLinq request to detect methods to refactor.

So only 1% of methods can be considered as complex.

Which methods are complex and not enough commented?

Methods with many variables

Methods where NbVariables is higher than 8 are hard to understand and maintain. Methods where NbVariables is higher than 15 are extremely complex and should be split in smaller methods (except if they are automatically generated by a tool).

Only 8 methods has too many variables.

Types with many methods and fields

Only 3% of types has many methods.

And we can do the same search for fields

Less than 1% of types has many fields.

We can say that POCO is well implemented,few methods are considered complex,the types are simple with few methods and fields and it’s well commented.

DESIGN

Abstract vs instability

The “Abstractness vs Instability” graph can be useful to detect projects that will be difficult to maintain or evolve.
This following post describe the utility of this graph and how to exploit it to improve the design.

For POCO here’s the “Abstractness vs Instability” graph:

Only Fondation is inside the zone of pain , it’s normal because it’s very used by other projects.

Inheritance

Multiple inheritane increase complexity ,and we have to use it carefully.

Let’s search for class with many base classes.

The blue rectangles represent the result.

only few classes derived from more than one class.

Type 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.

Only 1% of types are considered as no cohesive.

Efferent coupling

The Efferent Coupling for a particular type is the number of types it directly depends on.
Types where TypeCe > 50 are types that depends on too many other types. They are complex and have more than one responsability. They are good candidate for refactoring.

Let’s execute the following CQLinq request.

And the result is empty so no class has many responsibilities.

Types most used

It’s very interesting to know which types are most used,for that we can use the TypeRank metric.

TypeRank values are computed by applying the Google PageRank algorithm on the graph of type’s dependencies. A homothety of center 0.15 is applied to make it so that the average of TypeRank is 1.

Types with high TypeRank should be more carefully tested because bugs in such types will likely be more catastrophic.

Let’s search for types most used and complex.

The result is empty so no class is very used and complex.

Layering and level metric

This post explain the level metric and how to exploit it to improve design.

Let’s search dependency cycles for that we can execute the following CQLinq request:

Only few methods has dependency cycle, let’s take for example the Zip project and look to its dependency graph.

Only 1 dependency cycle exist in this project.

As conclusion Poco is also well designed, it’s high cohesive and low coupled.

Immutability to the rescue

There is a powerful and simple concept in programming that is really underused: Immutability.
Basically, an object is immutable if its state doesn’t change once the object has been created. Consequently, a class is immutable if its instances are immutable.

There is one killer argument for using immutable objects: It dramatically simplifies concurrent programming. Think about it, why does writing proper multithreaded programming is a hard task? Because it is hard to synchronize threads accesses to resources (objects or others OS things). Why it is hard to synchronize these accesses? Because it is hard to guarantee that there won’t be race conditions between the multiple write accesses and read accesses done by multiple threads on multiple objects. What if there are no more write accesses? In other words, what if the state of the objects threads are accessing, doesn’t change? There is no more need for synchronization!

Immutable classes are also well adapted to be key in hashtables,The objects on which the hash values are computed must be immutable to make sure that the hash values will be constant in time. Indeed, hash value is computed from the state of the object.

A famous immutable class

There is one famous immutable class: System.String. When you think that you are modifying a string, you actually create a new string object. Often, we forget about it and we would like to write …
String str = ”foofoo”;
str.replace(“foo”, “FOO”);
…where we need to write instead:
str = str.replace(“foo”, ”FOO”);

Of course, doing so comes at the cost of creating multiple string objects in memory when doing some intensive string computation. In this case you need to use the StringBuilder class.

Domain Driven Design and Immutability

The Domain Driven Design is an approach to the design of software, based on the two premises:

  • That complex domain designs should be based on a model,
  • And that for most software projects, the primary focus should be on the domain and domain logic (as opposed to the particular technology used to implement the system).

In other words the heart of the DDD is Model and the first thing to do when starting development is drawing the model. Model and design you create should shape each other. Model should represent knowledge of the business.

In general the shared data between thread concern the model entities. And making them immutable will eliminate side-effects. I couldn’t say it better than Wes Dyer so I quote him:


“We all know that generally it is not a good idea to use global variables. This is basically the extreme of exposing side-effects (the global scope). Many of the programmers who don’t use global variables don’t realize that the same principles apply to fields, properties, parameters, and variables on a more limited scale: don’t mutate them unless you have a good reason.(…)”

One way to increase the reliability of a unit is to eliminate the side-effects. This makes composing and integrating units together much easier and more robust. Since they are side-effect free, they always work the same no matter the environment. This is called referential transparency.

Immutability support in JArchitect and CQLinq

As we saw, immutability is a feature that can be enforced at compile-time. In other words it can be enforced by static analysis tools. Thus, the Code Query on LINQ feature (CQLinq) that comes with the static analysis tool JArchitect has an IsImmutable condition that applies on types.

To know which types of your code base are immutable it is as easy as writing this CQLinq query:

from t in Types where t.IsImmutable select t

To constraint a particular type MyNamespace. Foo to be immutable you can write this CQLinq constraint:

warnif count != 1
from t in Types where t.IsImmutable && t.FullName==”MyNamespace.Foo”
select t

To constraint a range of types used by the class MyNamespace. Foo to be immutable:

warnif count != 1
from t in Types where t.IsImmutable && t.IsUsedBy(”MyNamespace.Foo”)
select t

We can search for mutable classes derived from a class.

warnif count>0
from t in Types where t.DepthOfDeriveFrom(“Foo.ImmutableClass”)>=0 && ! t.IsImmutable
select t

And also all mutables classes inside a namespace hierarchy.

warnif count>0
from t in Application.Namespaces.WithNameWildcardMatchIn( “Foo.Model”).ChildTypes() where t.DepthOfDeriveFrom(“Foo.ImmutableClass”)>=0 && ! t.IsImmutable
select t

So, what’s behind the IsImmutable CQLinq condition? Here are the rules that JArchitect uses to decide if a type is immutable or not:

  • A type with at least one non-private instance field is considered as mutable (because such a field can be eventually modified outside of the type).
  • A type that has a method that is not a constructor and that assign an instance field is considered as mutable.
  • A class that derives directly or indirectly from a mutable type is considered as mutable.
  • Enumeration, static type, type defined in third projects are never considered as immutable. Although these types might match the definition of immutability, considering them as immutable would disturb developers while they care for their own immutable types.
  • Particularly, classes that derive directly or indirectly from a class defined in a third project are never considered as immutable.

Beside the IsImmutable condition on types, we also added 2 conditions on methods: ChangesObjectState and ChangesTypeState.

As the name suggest, ChangesObjectState match methods that are assigning an instance field of its class and the ChangesTypeState match methods that are assigning a static field of its class.

The condition ChangesObjectState matches constructors and static method. The condition ChangesTypeState matches constructors, instance methods and static methods.

These 2 conditions can be used to see at a glance which methods can change the state of your program, in other words, which methods are mutable or non-const, or better said, which methods provoke side-effects.

And as Wes Dier wrote: One way to increase the reliability of a unit is to eliminate the side-effects.

Typically a method that doesn’t provoke side-effects is said to be a pure method. To match pure methods with CQLinq one can write:

from m in Methods
where !m. ChangesObjectState && !m. ChangesTypeState && !m.IsConstructor
select m

Eliminate the side-effects makes composing and integrating units together much easier and more robust, and simplify multithreaded programming.