Tag Archives: Functional Cohesion

Refactoring: strategy & collaborative work

Introduction –  The extended definition of Refactoring contains also this part:  “Its heart is a series of small behavior preserving transformations. Each transformation (called a “refactoring”) does little, but a sequence of transformations can produce a significant restructuring. Since each refactoring is small, it’s less likely to go wrong. The system is kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring.”- Martin Fowler, at refactoring.com.

Note: this imaginary dialog it’s inspired from an intensive and extensive practice.

What if we will have to perform a Big Refactoring? 

Refactoring cannot be big, it is a special kind of redesign, performed in small steps. See the above definition again.

Reformulate: I need to do a lot of refactorings to clean a legacy code.  There is any best practice?    

You need a strategy?

Yes!

Well, agile and software engineering offer a lot of tactics, including the Martin Fowler refactoring sets but almost no strategy, except … you should work clean from the first time. Use Martin Fowler indications from the start (or early enough), also Uncle Bob Clean Code and Clean Architecture.

Hey! I already have a lot of legacy code debt to solve!

Ok! Let’s build a strategy: how do we start?

This was my question!

Refactoring supposed improving the design, while preserving the functionality. Tests included. Do you have good requirements specifications or a good set of automated tests?

Not in this case.

Then you should recover functionality knowledge from the code and put/perform incrementally some tests. Better: functionality should be explicitly represented in the code and should be testable. And remember: there are two kinds of functionality…

Two?

Yes, first, the one that is application-independent and represent the target domain (domain business rules) and the one that is application-depend aka flow of control.

I remember: that sound like Uncle Bob Clean Architecture.

Yes. You will need to be able to apply distinct tests to them, without mix them with other concerns such as UI, persistence, network and others. Anyway, where do I usually start? I will try to make the running scenarios very clear into the code and that mean the flow of control.

In English, please?

I want to clearly see these: were the event triggered by the system actors start and the end-to-end full path until return. More, I want to refactor to make this path clear enough.

How could be not clear? ­­­

Global context. If the functionality path chaotically accesses the global context, then we could have undesired intersections with other paths/scenarios, that will compromise both data and function. In the same time, we can decouple flow/orchestration from specialized concerns.

What we get?

We will have explicit representation of the functionality (with no undesired contacts with other flows), needed for tests (we can apply auto-tests on it). Also we will have the first entry points to the specialized parts that also could be <decorated> with some tests. Then we can apply tactical refactoring as we need.

And …the domain business rules?

Must be decoupled from other concerns and you have to dedicate them specialized design/test elements.

That’s all?

Almost. You need to test any redesign. Tests need knowledge about functionality. If some parts are missing, now it is the time to recover them in auto-tests (preferable) or in other form of specification.

How do I know that recovered requirements are correct?

You don’t. More, you should always suspect that spaghetti-like legacy code include many unobserved bugs. You should validate these functional requirements by intensive collaboration with your colleagues, with domain experts, customer and other stakeholders.

Do you have any idea about how to do that?    

Start with Pair Programming (refactor in pairs). Pairing is not enough, and you will probably need more people involved – use Model Storming: discuss the resulted functionality with more colleagues.

Model Storming?

Yes, it is an agile practice, part of Agile Modeling (and Disciplined Agile) and it was created to complement core practices from XP. Also, you should actively involve your stakeholders in validating the recovered functionality…. Active Stakeholder Participation, that it is another Agile Modeling recommended practices. And at the end you will have more free bonuses.

What bonuses?

Functionality it is easy to accurately read from code (seconds!) and your colleagues and your stakeholders will already have acquired the recovered functional knowledge.

Summary –  Refactoring for significant spaghetti legacy code need tests/testing. Usually, knowledge about functionality necessary for testing it is insufficient, so must be recovered from the code. An effective & proven way to do that is to apply Clean Architecture principles: decuple both domain rules and application specific flow of control (aka use cases). Anyway, legacy code with too much technical debt will contain a lot of bugs, so recovered functionality it is inaccurate and need to be validated.  Knowledge & expertise needed for validation it is distributed among team members, domain experts, customers and other stakeholders, so you need to work in a collaborative manner with all mentioned parts. There are some outstanding software engineering and agile practices that could help on this aspect:

Note: “need” and “necessary” are often use in above text, just because we have followed the logical path of necessary things for testing a redesigned legacy code.

Remember: A lot of technical debt ~ inaccurate functionality. To refactor & test, you must re-start the process & collaborative work from functional requirements acquisition.     

Before DevOps: Delivering more by delivering less

Undesired complexity give undesired deliveries

There are many aspects to consider related to DevOps and delivery, many strategies and (in the right context and the right approach) there are also some very useful tools. It is a complex issue and last thing that we want is to make that even harder because of undesired complexity. A poor and an un-appropriate design is the main cause of the problems.

Suppose that the main aspects of a product functionalities and design are the followings:

  • Functionalities: f1, f2, f3
  • Business rules: r1, r2
  • External frameworks, technologies, and drivers (APIs, hardware interfaces, others) e1, e2
  • External interfaces: i1, i2,
  • Technical mechanisms: t1, t2, t3..

Should stay together only what it changes and should be deliver together.

As generic rule, if one of this aspects it is changed, we do not want to affect, change and deliver others aspects. Below are some examples of anti-patterns.

Anti-pattern: Lack of functional cohesion

Just a start example: If was requested to deliver a change for the functionality f1, it is highly undesired to change also functionalities f3 and f4 only because f1, f3 and f4 are unnecessary coupled in the implementation. This coupling could mean: same function, same class or same package as opposite of using distinct design elements.

Anti-pattern: Non-DRY business rules

If the business rule r1 it is used in more functionalities (that have dedicated components) and that rule implementation is duplicated (multiplied) in every functionality, then a change in r1 will require change and delivery for all those functionalities and components.

Anti-pattern: Mixing functionalities with external communication

Suppose that f1 and f2 are using TCP sockets for communication with some external systems and we need to replace this type of communication, if the f1, f2 implementation is mixed with socket management aspects, then we need to change and deliver also f1 and f2.

Anti-pattern: Mixing functionalities with external interfaces

External interfaces could suppose handling of some specific external data structures and/or of some specific communication protocol. If we are mixing these parts with internal functionalities, with any change in the interface, we should change and deliver also some not related internal parts, .

Anti-pattern: Mixing functionalities with technical aspects

You need to protect the representation of the business inside the product from the changes related to technology. Where is the technology involved? Any I/O aspect that wrap the hardware: GUI, network, databases, file systems is strongly related to technologies and platforms. If, for example, you have a lot of functionality and business representation in the design of the GUI elements, any change in GUI technologies will affect the business representation inside the product, that should also massively changed and then delivered.

Anti-pattern: “Utils”

A symptom of a poor design that could cause undesired supplementary work on development and delivery are the “utils” packages, especially without clearly dedicated sub-packages. Examples:

  • “utils” package that mix together classes belong to different functional aspects
  • “utils” package that mix various technical aspects without having dedicated sub-packages

This kind of design suppose that we need to change, test and deliver the “utils” almost with any change of the product.

Anti-pattern: Dirty code

Breaking simplest Clean Code rules (similar with the ones that are used in refactoring) could cause undesired coupling and undesired increase of delivery scope. Some examples that could induce such problems:

  • Any duplicate/multiplied code
  • Breaking SRP principle
  • Global context data, global variables (breaking Law of Demeter)

Minimizing the need of change and delivery

We need to reduce the need of change and delivery only to the required ones. There are several practices and approaches that could avoid that problem (the examples presented above or similar ones):

  • Keep the code clean by writhing Clean Code first and refactor and pay the technical debt whenever it is necessary
  • Use functional cohesion as the main criteria of creating components and packages
  • Use Clean Architecture that propose a default, strategic separation of concerns
  • Extend XP engineering practices (Simple Design, Refactoring, TDD) with the ones from Agile Modeling and DAD
  • Respect Law of Demeter on any level of the design – do not use any global context
  • Make the products adaptive by keeping up-to-date with target business by often and early injection of feedback from that business.

You can argue that I already write about all these in a previous post “Roadmap to an Agile Design”. Yes, indeed, in order to deliver just what it is needed and avoid waste you must have an Adaptive Design, the main characteristic of an Agile Design.

In order to that you should be open  to all outstanding agile practices for design and do not be closed in the smaller universe of some very lightweight Agile methods. And remember that those lightweight methods are not created as full process methodologies, but as indications to build a customized process.

Imagine that all these problems are far worse if we have multiple variations and variants of the same product. The massive effort for any change and delivery will block the overall agility and responsiveness of the development team and massively reduce the overall economics for both development and customer side.

Use a strategic separation of concerns

Do not use any reference to any global context

Upgrading Refactoring: Clean vs Adapt, Clean Code/Refactor/Re-Design

If I had to pick one thing that sets XP apart from other approaches, it would be refactoring, the ongoing redesign of software to improve its responsiveness to change.  – Jim Highsmith

The easiest technical debt to address is that which you didn’t incur to begin with. – Scott W. Ambler

 Refactoring definition – What, How and Why

There is a great work related to Refactoring, starting with the book “Refactoring: Improving the Design of Existing Code” of Martin Fowler and its collaborators (Kent Beck, John Brant, William Opdyke, Don Roberts) and continuing with the XP – Extreme Programming ecosystem of practices, that include Refactoring as the fundamental Agile practice.

The definition from Martin Fowler, at www.refactoring.com:

<<In the Refactoring Book, I made the following definition of “Refactoring”

 noun: a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior

 verb: to restructure software by applying a series of refactorings without changing its observable behavior

 Refactoring isn’t another word for cleaning up code – it specifically defines one technique for improving the health of a code-base. I use “restructuring” as a more general term for reorganizing code that may incorporate other techniques.>>

Some comments:

  • The objective could be generalized: Improving the design of existing code, without changing the observable functionality, must be performed for improving the health and economics of the software, where “easier to understand and cheaper to modify” are only some of the objectives (others: less defects, easier to detect the defects)
  • Clean is just one “technique“… Which are the others?
  • The extended definition contains also this part:  “Its heart is a series of small behavior preserving transformations. Each transformation (called a “refactoring”) does little, but a sequence of transformations can produce a significant restructuring. Since each refactoring is small, it’s less likely to go wrong. The system is kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring.”- Martin Fowler, at refactoring.com.

Improving the design of existing code, without changing the observable functionality, must be performed for improving the health and economics of the software.

.

Refactoring versus waste – Clean versus Adapt

Refactoring offers a process solution for design flexibility. A possible approach for getting a flexible solution could require some up-front design based on imagined future requirements. In many cases, these requirements never become real and that it is a waste. Martin Fowler says: “Refactoring can lead to simpler designs without sacrificing flexibility. This makes the design process easier and less stressful. […] Once you have a broad sense of things that refactor easily, you don’t even think of the flexible solutions. You have the confidence to refactor if the time comes.

In this case, the better design will come later, when the new context will be revealed.

Let’s think about some other kind of refactoring types, the ones that fix the majority of the design smells such: function and classes’ sizes, multiple responsibilities, magic numbers, duplicated code, meaningful names, comments and others. In this case, when these rules are applied or corrected later, the waste is bigger and even in exponential manner.

That seems contradictory: sometime it is better to refactor later and sometime is better to refactor sooner. Well, it is not! “Flexibility” and “Design smells” are two different problems.

There are two kinds of design decisions involved here:

  • Context independent – the ones that makes the code clean
  • Context dependent – the ones that are adapted to the current context

 Clean and Adapt are two different things and each one must be managed accordingly.

The sequence of decisions related to the design could be like this:

  • First development: Simple and clean first code – apply Simple Design and Clean Code. Use some “in development” refactoring, but try to write clean from the first time.
  • Next development: Adapt the first simple and clean design to the new context and perform also necessary cleaning.

The statement “You build the simplest thing that can possibly work.” should be reformulated as “You build the simplest clean thing that can possibly work”.

Sources of waste: any wild guess about future contexts, but also any mess remaining from previous development.

.

Reformulating the process

We have two kind of activities: Clean and Adapt and more practices that could realize their objectives:

  • Clean Code – write the code clean from the first time
  • Refactor – improve the design, while preserving observable behavior; executed in small transformations, while keeping the system stable
  • Redesign – similar with refactoring, but not necessary in small steps (with increased risks)

.

Clean Code & Refactoring

Both practices are introducing a set of design rules, specified in two books, where “Clean Code” it is creation of Robert C. Martin and “Refactoring: Improving the Design of Existing Code” of Martin Fowler and its collaborators (Kent Beck, John Brant, William Opdyke, Don Roberts). Logically it is a single set of rules that:

  • Keep the code clean
  • Are rather context independent

.

Keeping the code clean – practices and approach

In most of the cases, the design decisions related to a clean code are context (requirements) independent. In order to eliminate waste, the code could be kept clean as follows, using these practices:

  • Clean Code: write the code as clean it is possible from the first time
    • Refactor “in development”: earliest refactoring, during the development is the cheapest
  • Refactor “legacy”: paying the debt of dirty code as early is possible is the cheapest variant, when the debt already exist
  • Re-design “legacy”: only in cases where Refactoring (small steps) it is not possible, because the risks are increased in this case and the testing it is more difficult.

Simple Design it is considered as default complementary practice for all these cases.

Sources of waste:

  • Writing first code dirty is the most massive source of Technical Debt and refactoring it is not efficient/effective
  • Technical Debt reduce productivity, quality, agility and increase system rigidity and fragility
  • The cost of paying the Technical Debt could increase exponentially when it is accumulated in high amounts of dirty code

.

Adapt Design rules – practices and approach

These kind of decisions – adapt the design – are context dependent. In order to eliminate waste, the best time to take such decisions is to defer them until the context it is revealed. A possible approach could be:

  • Respect the above clean code rules
  • Simple (Design) and Clean (Code) – “build the simplest clean thing that can possibly work” for the current context/requirements
  • Adapt “legacy” design in new context – adapt the previous simple design to the new context /requirements, when this new context it is revealed (Simple Design it is applied again):
    • By Refactoring
    • By Re-design ( see comments for re-design from Clean Code rules)

Important: Refactor/Re-design to adapt the previous design must be done when this previous design does not match exactly to the new context. There are some practices that for Adaptive Design that increase the chance for an emergent design with less work related to adaptation – See “Roadmap to an Agile Design.

Simple Design Formula: Simple Design (context 1) + Adapt & Simple Design (context 2) + …

Sources of waste:

  • Premature design decisions based on wild guesses about future requirements, as opposite to Simple Design
  • Skipping the adapt design decisions needed in the new context
  • Trying to evolve the design only with these adapting tactical steps without any strategic approach for emergent design as Functional Cohesion and Separation of Concerns from Clean Architecture

Effective/Efficient “Clean”: clean and simple design first and then refactor.

Effective/Efficient “Adapt”: clean and simple architecture (& design) first and then adapt.

.

Process level upgrades – DAD style

The above logic could be re-formulated, refactored (sic!) again in terms of:

  • Process goals: keep the code clean, adapt the design (previous simple design in new context)
  • Goal options: An alternative for Refactoring is Re-design, where Refactoring is the default option and Redesign (with increased risks) should be considered only when the Refactoring is not possible
  • Note: Strategic options are complementary to tactical options and not alternatives

This process level logic it is used by DAD – Disciplined Agile Delivery, and finally help to fill the process gaps from other methods or a custom process and offer a much better support for process guidance.

For the Adapt goal ,  Refactoring is the core tactical technique, but in fact there are many practices that contribute to this goal:

  • Examples of tactical practices for Adapt goal: Refactoring, Test first, Re-design, Model Storming, Look Ahead Modeling.
  • Examples of strategical practices for Adapt goal: Clean Architecture, Continuous Integration.

More: a generic goal it is Design Envisioning & Change,  where the two main aspects are what is new and what is adapted. For an Agile context, based on Simple Design, the Adapt aspect is fundamental and has a “big share” in the process.

 There is not only Simple Design, there are “twins”: Simple Design + Adapt

Roadmap to an agile design

“You can’t have a culture without practices; and the practices you follow identify your culture.”  
(Robert C. Martin) 

BROKEN PROMISE

Eng versus practiceThere is a huge imbalance between the Agile promise and what it is obtained with the usual set of Agile engineering practices.

 Why?

The common approach is to use the Agile methods such Scrum and XP as recipes or as a “closed universes”, by using only the engineering practices prescribed by the methods. Any other proven and outstanding practices are rather rarely used.

The standard set of practices – Simple Design, Refactoring, TDD – does not cover some significant problems:

  • Refactoring is not effective & efficient if the first code is too dirty.
  • None of these practices specify how to protect the business representation inside the software system against the changes related to technologies
  • None of these practices can guarantee that changes in the customer business could be introduced in the software product with high efficiency/effectiveness

We need to go outside the methods and discover what the industry could offer for an Agile Design in order to keep that promise.

.

SUMMARY

generic, specific Introduction – we need to go outside the recipes to put together all the industry strength, in order to fix the imbalance between the used practices and the Agile promise.

AGILE PROMISE – an Agile approach should offer good (sustainable, available, effective, efficient) results for adaptive problems/adaptive context (quick, often, even late) (See Agile Manifesto).

Engineering support – usually, in the best cases, this support does not go further than these three practices: simple design, refactoring and TDD.

What is missing – good enough support for efficiency/effectiveness on: keeping a clean code, business changes or technology changes. We need to define this support for gettting/maintaining an AGILE DESIGN.

The roadmap to an Agile Design – we need to find the minimal set of indispensable, context agnostic, design related practices to get/maintain an Adaptive Design and an Adaptive Product.

The “recipe” problem – the usual tendency is to use only the “inside methods” design practices and to ignore any other useful practices.

Aspects to be considered – the selected practices must cover capability of being adaptive:

  • For design level and architecture level aspects;
  • For process aspects that support envisioning of the initial design, cleanup of technical debt, quick quality check and adherence to business needs and their changes.
  • For realizing the design principles that support building of adaptive products.

Indispensable practices for an Agile Design – by levels:

  • DESIGN LEVEL
    • Clean Code, Refactoring, Applying Law Of Demeter, Programming Style
  • ARCHITECTURE LEVEL
    • Clean Architecture, Applying Law Of Demeter
  • PROCESS LEVEL
    • Architecture Envisioning, Look Ahead Modeling, Model Storming,  Refactoring, TDD, Simple Design, Non-Solo Development, Product Backlog, Continuous Integration

Indispensable principles for an Agile Design – Single Responsibility (of a design element), Separation of Concerns (in enhanced mode, with Dependency Inversion), Functional Cohesion, Law of Demeter.

Final thoughts: Any of these principles and practices are pillars on getting and maintained an Agile/Adaptive Design Even some of them are rarely used, are already defined and proved by major contributors to Agile knowledge and software industry. Also, my personal experience found the selected practices and principles very useful.

.

AGILE PROMISE

 The promise – Good and Adaptive

Agile approach main promise is to be always ready to respond quick, effective and efficient to often changes, even late, in customer business needs. Thant mean we have two kinds of promises:

  • GENERIC – good results
    • always – sustainable and available
    • effective
    • efficient
  • SPECIFIC – adaptive
      • quick
      • often
      • even late

If you have any doubts about these things, please review the Agile Manifesto (see [B-AM]) and the main original Agile methods as XP-Extreme Programming and Scrum. Can be easy observed that all the engineering and management practices are especially selected (in the principles and methods) to get good results, but for rather adaptive problems (Scrum explicitly declare that).

Engineering support

In order to keep that promise, the used engineering practices must be aligned to the declared goal. In my previous post, I have notified the necessity to build and maintain the software products as Adaptive Product in order to have and maintain the Agile capability. A significant aspect in getting this kind of product is to select and use all necessary design practices to get/maintain this capability: we need an Agile Design as an Adaptive Design.

If an Agile practitioner it is asked about this engineering support, the most probable answer is: “we are successfully using refactoring, test driven development and simple design”. All these are great practices and an engineering process that use them could be also great. The question is: if we are using all these practices we could still have significant problems with adaptability?

Unfortunately, the answer it is “yes” (See “Broken Promise”)

Another question: there are other agile practices that could solve these kinds of problems? The answer is “yes”, but are rarely used.

What is missing to keep the promise?

All the mandatory design practices necessary to keep the promise must be put together in a coherent set. Now, only XP have a set of core design practices, but is incomplete and does not cover all aspects of an adaptive design.

.

ROADMAP TO AN AGILE DESIGN

The roadmap – restoring the balance

restore balanceWe need to restore the balance – to find an Agile Design as an Adaptive Design that keep the Agile Promise. For that we need to find good enough set of design practices that could provide and cover the main design aspects.

praticesWe are looking for design related practices that:

  • Are generic, not context dependent
  • Indispensable for the “adaptive” property of the resulted software system
  • Part of the industry knowledge and experience

Some comments about context dependency: a practice is generic if should be always used and considered and the only context-depended question is “how”.

The problem – methods as recipes

Among the known practices for an Agile design, just a subset are “inside methods” practices, that mean explicitly specified in the Agile methods as XP, Scrum, DAD (Disciplined Agile Delivery). Many other very interesting practices are described by the main contributors to the Agile knowledge, but not as part of some methods.

Practice Proposed by Inside method Degree of usage*
Refactoring XP XP Rather often
Simple Design XP XP Rather often
TDD XP, Scrum XP Sometime
Clean Code Robert C. Martin Rather rare
Clean Architecture Robert C. Martin Rather very rare
Non-Solo Development Scott W. Ambler DAD Rather rare

Note (*) – Degree of usage is based on published statistics and by the observable number of references to these practices.

Unfortunately, in most cases, only “inside methods” have a larger adoption, because the Agile methods are used as “recipes” (… not in thein intention of the authors) or “closed universes”, where the practitioners avoid to assuming process responsibilities outside the methods border.

The consequence: some fundamental practices are rarely used and the resulted products are less adaptive because of their less adaptive design. The Agile promise is broken.

 .

SOLUTION – defining a set of indispensables practices

coverageWe need to find the set of indispensable practices for an Agile Design, but we need to be sure that we have enough coverage for all significant design-related aspects that will help us to keep the promise to be adaptive.

ASPECTS OF AN ADAPTIVE DESIGN – selected list:

  • Design principles
    • DPs that contribute to an adaptive design
  • Design level
    • Design context agnostic best practices to keep the product adaptive
    • Architecture context agnostic best practices to keep the product adaptive
  • Design process
    • Cleanup of the technical debt
    • Fast quality checks
    • Adherence to business needs and changes (efficient and effective)
    • Knowledge management in adaptive context
    • Evolving solution and effects on project definition

INDISPENSABLE PRACTICES PER ASPECT – Then, for each aspect, we need to find the sine-qua-non (indispensable) practices to deal with that aspect. This is the proposed list:

Aspects category Aspects Practices
Design level Adaptive design support Clean Code, Refactoring,Programming Style, Law of Demeter (applying)
Architecture level Adaptive design support Clean Architecture, Law of Demeter (applying)
Process level Pay the technical debt Refactoring
Fast quality check TDD
Adherence to business needs Simple Design, Product Backlog, Clean Architecture
Knowledge management Non-Solo Development, Product Backlog
Evolving solution, Project Definition Architecture Envisioning, Look Ahead Modeling, Model Storming, Continuous integration

Observations:

  • From similar practices are selected the ones with higher coverage.
  • Practices are inter-dependent and each of them will contribute to all the aspects and will enhance the results of the others
  • The selected practices must realize the selected design principles

INDISPENSABLE PRINCIPLES FOR AN ADAPTIVE DESIGN – These principles are part of the industry proven experience and are in the top recommendations for a good design a technical excellence. The other reason for including them in an agile related list is the contribution to the “adaptive” property of design.

Single Responsibility (of a design element): isolating responsibilities in functions, classes, components, services, sub-systems will make the system easy to build, change and maintain (… where the reasons are already part of the industry experience).

Separation of Concerns: that it is a higher level aspect of SR principle, where separation is rather considered at architectural level (layers, sub-systems) and the concerns are also high-level responsibilities (presentation, business, persistence, hardware interfaces, cross-cutting concerns). Each of these concerns could independently change and without decoupling them, the system will not be adaptive.

Functional Cohesion – that it is starting architectural/design decision that declares as main subjects of separation and decoupling:

  • Business concerns from technological concerns
  • Business concerns parts/functions from each other
  • Could be applied at any design level sub-systems, components, classes, functions

Law of Demeter – See “Practice – Applying Law of Demeter”

It is impossible to explain that you have an Adaptive Design and you will keep the Agile promise and also do not respect these principles.

 .

PRACTICE – XP practices: this is how Agile works

The good part is that XP (see [B-XP]) it is an wonderful representation about how Agile fundaments are working. Here we will talk just about Simple Design, Refactoring and TDD. These practices are helping to keep the toughest agile promises from the Agile Manifesto:

  • “…satisfy the customer through early and continuous delivery of valuable software.”
  • Welcome changing requirements, even late in development

Each of these practices will have its fundamental role:

Simple design – XP: “always do the simplest thing that could possibly work next”.

  • Request to focus only to current requirements, without trying to extrapolate the future ones. After a sequence of small releases, we will have a design properly adapted only to current business needs, not to hypothetically or obsolete ones (“junk stories”). Simple design means to be both focused and clean.

INDISPENSABLE – If Simple Design it is not used, then:

  • Increasing technical debt and waste caused by guessing future needs instead of waiting the new business context to be relieved. Increasing amount of implemented junk stories

Refactoring – Martin Fowler: “Improving the design of an existing code” by “applying a series of small behavior-preserving transformations

INDISPENSABLE – If Refactoring it is not used, then:

  • The technical debt is accumulating in high amounts and the code will NOT be cleaned, easy to read, to understand and change. The productivity will decrease and the product will be more fragile until becoming completely unstable
  • The previous simple design must be adapted to new requirements, and refactoring it is one of the most effective techniques

TDD – automatic tests, with high coverage at unit test level; the tests should be writing first.

INDISPENSABLE – If TDD it is not used, then:

  • There is no other technique to support QA/QC concerns in dealing with changes that occur “late in development” and that could offer quick, effective and efficient safety net for refactoring necessary regression tests
  • There is less separation of concerns

.

PRACTICE – Non-Solo Development (DAD)

XP introduce Pair Programming as essential Agile practices. The main meaning is to have “cooperative programming”. Unfortunately, this practice it is used too literally, only for direct coding activities. Yes, Agile has restored the importance of the coding in the overall development, but let think a little: what is the meaning of “Programming” from XP name? In fact, it is “Development”, where the effective programming/coding has fundamental importance. An XP programmer it is, in fact a multi-role developer involved also in planning, requirements, architecture, and design, coding and testing.

In DAD, Scott W. Ambler has introduced the term “Non-Solo Development” for a cooperative development approach that combines various kind of pair-development with solo-development.

INDISPENSABLE – If cooperative development it is not used, then:

  • All the needed design practices cannot be applied coherently and consistent
  • The needed design decisions will be rather under a minimum threshold of effectiveness and efficiency
  • The skills and the knowledge of the team will not match to the necessities
  • Agile process will not be enabled

.

PRACTICE – Product Backlog (Scrum)

The Product Backlog it is a very used practice, but its impact in the design is less known.

Note: An enhanced variant of the Product Backlog is the (Product) “Work Item List” from DAD.

INDISPENSABLE – If Product Backlog it is not used, then:

  • The work will not be serialized and refined in clear increments before starting the main development effort (iteration level)
    • Consequence: Not enough support for realizing a Simple Design,
    • Consequence: Paying the Technical Debt (using Refactoring or other techniques) has poor support on planning and visibility;
    • Consequence: less support to effectively connect to change requests and customer feedback in order to get and maintain Adaptive Products.

.

PRACTICE – Architecture Envisioning (AM, DAD)

AM (Agile Modeling) make explicit the architectural concern that should be addressed early in the development as Architecture Envisioning. This is the place where should be taken also the initial decision about Clean Architecture and most significant decisions related to Refactoring and TDD. (See [B-SWA])

INDISPENSABLE – If is not used, then:

  • The main technical risks will not be addressed early with all the resulted consequences
  • The planning will have no real support , because the necessary work it is mostly unclear.
  • The Clean Architecture rules cannot be applied (in the envisioning must be clarified how will be applied)
  • Decisions related to significant refactoring and to high level decoupling needs related to TDD cannot be taken at the appropriator time

.

PRACTICE – Look Ahead Modeling (AM, DAD)

AM (Agile Modeling) make explicit the design risks and complexity concerns that should be in advance in the development (as a refining of Architecture Envisioning) , as Look Ahead Modeling. This is the place where should be taken also tin significant decisions related to necessary  Refactoring  and TDD . (See [B-SWA])

INDISPENSABLE – If is not used, then:

  • The undesired complexity of the design will increase in the most sensible places
  • The plan updates and progress tracking are affected because of not updated information about solution
  • The TDD, Refactoring and Clean Code significant decisions will be affected

.

PRACTICE – Model Storming (AM, DAD)

AM (Agile Modeling) make explicit the design complexity concern that should be addressed JIT (Just-In-Time) in the development, when is needed,  as Model Storming . This is the place where should be taken also the possible decisions related to necessary  Refactoring  and TDD . (See [B-SWA])

INDISPENSABLE – If is not used, then:

  • The undesired complexity of the design will increase in the most sensible places
  • The TDD, Refactoring and Clean Code decisions will be affected

.

PRACTICE – Clean Code

The clean code rules are introduced by Robert C. Martin (see [B–CC]). Of course, there is an intersection and similarity with the refactoring rules introduced by Martin Fowler. The difference is rather at process level: Clean Code supposed also to write the proper code from the first time, combining with continuous cleaning and refactoring. In fact, we can combine Clean Code, Refactoring and other similar rules in a one single set where:

  • Clean Code is what we can want to obtain as code state/attribute
  • The first time code must be clean enough
  • Refactoring is the operation to pay some technical debts and get closer to the Clean Code state

Clean Code as a practice should represent all the small design and design level best practices that are generic, context agnostic and address most generic causes of producing the technical debt.

Examples of subjects for clean code rules: meaningful names, functions and class creations, comments, unit tests, building systems, simple emerging design and others. Example of generic rules and (solved) problems: avoid feature envy, misplaced responsibility, make logical dependency physical.

INDISPENSABLE – If clean code rules are not used, then:

  • Will be activated the causes that produce the most amount of technical debt – the code mess is systematically produced in huge amount.
  • The code will be hard and very expensive to read, change and fix

.

PRACTICE – Clean Architecture

The Robert C. Martin concept of Clean Architecture (see [B–CA]) suppose that according to the fundamental design principle of Separation of Concerns we will take from the start some architectural decisions (because it is always useful and it is context agnostic):

  • Functional cohesion – the system functions must be visible in its design: various business concerns are separated by design and the technological concerns from the business concerns. The non-functional aspects must be isolated and should be considered as details (!), because things as the used technologies could always change, but the representation of the core business must survive.
  • Dependency injection – main way used to separate the various concerns

Alistair Cockburn proposes the similar concept of Hexagonal Architecture (see [B-HA]), as opposite to un-balanced architectures where only user-interface and persistence are driving the architecture, beyond the business part: “application communicates over ‘’ports’’ to external agencies”.

Koni Buhrer proposes the Universal Design Pattern (see [B-UDP]),, which gives little more details than the Hexagonal Architecture and could be a good approach to implement a Clean Architecture.

INDISPENSABLE – If clean architecture rules are not used, then:

  • the core business is NOT protected from technological changes, because it is NOT decoupled from those aspects
  • the core business is NOT realized using functional cohesion, the product will NOT have the “business DNA”, and cannot be an Adaptive Product (see my previous post), cannot be changed quick, efficient, effective and sustainable with customer business changes
  • Successive changes related to business change will produce design and architectural level technical debt – affect the overall productivity and quality
  • Similar undesired effects for successive changes caused by technologies aspects
  • (dramatically) Decrease the effectiveness of TDD, because best criteria of decoupling are not applied and both code and tests will be change too often on business and technological changes.

.

PRACTICE – Applying Law of Demeter

The Law of Demeter (LoD) or principle of least knowledge – “The fundamental notion is that a given object should assume as little as possible about the structure or properties of anything else (including its sub-components), in accordance with the principle of “information hiding”.”

It was also subject of more research and has influence development of more patterns. For Demeter project, Karl Lieberherr created a so called “Adaptive Programming” based on this principle (see [B-AP]).

In our days, the Google Talks presentations bring back into public attention the significant advantages of this principle. Using this principle should be a specific way to create objects and functions, a specific way to share and distribute data and information between them: in any part of our code we should not use references to a global context.

Respect of this principle it is fundamental to make possible all other best practices: concerns decoupling and functional cohesion.

INDISPENSABLE – If Law of Demeter is not used, then:

  • Separation of concerns, functional cohesion, clean code, and clean architecture are severely affected by breaking this rule. Consequences:
    • High amount of severe technical debt it is introduced (by using global context anywhere in the code)
    • The code fragility could dramatically increase (any change and fix could produce many new defects)

.

PROLOGUE (sic!)

I have selected these practices and principles for an Agile design from the intersection from what I know  from the industry experience and my personal experience. The starting point was that no Agile process method has included (from what I know) the Clean Code and Clean Architecture practices and, also, the principles aspect was ignored (exception: the above mentioned Adaptive Programming) .

When I tried to categorize the Refactoring and  Non-Solo Development,  I have added also the process aspect. Later, thanks to a feedback from Scott W. Ambler were added the missing Architecture Envisioning and design modeling practices.

I have tried to find past endeavors about:

  • defining some practices as indispensable, where only Adaptive Programming have used a such logic
  • unifying these indispensable practices for an Agile Design

I have found almost nothing, and the searches about “Adaptive Design”  found results only in furniture domain and was similar for “Agile Design.

Better late than never… just yesterday (September 28) I have discovered a previous definition of an Agile Design:

http://agilemodeling.com/essays/agileDesign.htm

That it is part of Agile Modeling method (Scott W. Ambler) and contain: Architecture Envisioning, Iteration Modeling, Model Storming, Test First Design, Refactoring and Continuous Integration. Some comments: I think that Iteration Modeling is a sub-practice of Look Ahead Modeling (but indispensable by itself) and that Continuous Integration is also indispensable.

.

BIBLIOGRAPHY

[B- HA] –Hexagonal Architecture, Alistair Cockburn

[B- UDP] –Universal Design Patterns

[B- AP] – Using Law of Demeter. Adaptive Programming. Brad Appleton

[B- AM]- Agile Manifesto

[B –XP] – Extreme Programming

[B – CA] – Robert C. Martin (Uncle Bob) – Clean Architecture and Design-2012 COHAA The Path to Agility Conference

[B – CC] – Robert C. Martin – Clean Code: A Handbook of Agile Software Craftsmanship, Prentice Hall, 2008

[B – SWA] – Scott W. Ambler – Agile Modeling

Motto – The True corruption of Agile – Robert C. Martin

%d bloggers like this: