Therefore, you should include maintainability as one of your design goals, along
with others such as reliability, security, and scalability.
Testability
A testable system is one that enables you to effectively test individual parts of
the system. Designing and writing effective tests can be just as challenging as
designing and writing testable application code, especially as systems become
larger and more complex. Methodologies such as test-driven development (TDD)
require you to write a unit test before writing any code to implement a new
feature and the goal of such a design technique is to improve the quality of your
application. Such design techniques also help to extend the coverage of your unit
tests, reduce the likelihood of regressions, and make refactoring easier. However,
as part of your testing processes you should also incorporate other types of tests
such as acceptance tests, integration tests, performance tests, and stress tests.
Running tests can also cost money and be time consuming because of the re-
quirement to test in a realistic environment. For example, for some types of
testing on a cloud-based application you need to deploy the application to the
cloud environment and run the tests in the cloud. If you use TDD, it may be
impractical to run all the tests in the cloud all of the time because of the time it
takes to deploy your application, even to a local emulator. In this type of sce-
nario, you may decide to use test doubles (simple stubs or verifiable mocks) that
replace the real components in the cloud environment with test implementa-
tions in order to enable you to run your suite of unit tests in isolation during the
standard TDD development cycle.
Testability should be another of the design goals for your system along with
maintainability and agility: a testable system is typically more maintainable, and
vice versa.
Flexibility and Extensibility
Flexibility and extensibility are also often on the list of desirable attributes of
enterprise applications. Given that business requirements often change, both
during the development of an application and after it is running in production,
you should try to design the application to make it flexible so that it can be
adapted to work in different ways and extensible so that you can add new fea-
tures. For example, you may need to convert your application from running
on-premises to running in the cloud.
Late Binding
In some application scenarios, you may have a requirement to support late bind-
ing. Late binding is useful if you require the ability to replace part of your system
without recompiling. For example, your application might support multiple re-
lational databases with a separate module for each supported database type.
You can use declarative configuration to tell the application to use a specific
module at runtime. Another scenario where late binding can be useful is to en-
able users of the system to provide their own customization through a plug-in.
Again, you can instruct the system to use a specific customization by using a
configuration setting or a convention where the system scans a particular loca-
tion on the file system for modules to use.
For a great discussion on the
use of test doubles, see the
point/counterpoint debate
by Steve Freeman, Nat Pryce
and Joshua Kerievsky in IEEE
Software (Volume: 24, Issue:
3), May/June 2007, pp.80-83.
Not all systems have a
requirement for late binding.
It is typically required to
support a specific feature
of the application such as
customization using a plug-
in architecture.
Using test doubles is a
great way to ensure that
you can continuously run
your unit tests during the
development process.
However, you must still fully
test your application in a real
environment.