UNIT - 3-Agile Notes
UNIT - 3-Agile Notes
UNIT - 3-Agile Notes
UNIT – III
AGILE SOFTWARE DESIGN AND DEVELOPMENT
Agile development makes the process of design and architecture continuous. It is also a way to
keep that design and architecture appropriate as the system grows and evolves over time.
Rigidity
Fragility
Immobility
Viscosity
Needless complexity
Needless repetition
Opacity
Rigidity
Rigidity is the tendency for software to be difficult to change, even in simple ways.
The more modules that must be changed, the more rigid the design.
Fragility
Fragility is the tendency of a program to break in many places when a single change is made.
Often new problems are in areas that have no conceptual relationship with the area that was
changed.
As the fragility of a module increases, the likelihood that a change will introduce unexpected
problems approaches certainty.
Immobility
A design is immobile when it contains parts that could be useful in other systems, but the effort
and risk involved with separating those parts from the original system are too great. This is an
unfortunate but very common occurrence.
Viscosity
When faced with a change, developers usually find more than one way to make
that change some of the ways preserve the design others do not.
We want to design our software such that the changes that preserve the design are
easy to make.
For example, if compile times are very long, developers will be tempted to
ininninchanges that don't force large recompiles, even though those changes don't
preserve the design. If the source code control system requires hours to check in
just a few files, developers will be tempted to make changes that require as few
check-ins as possible.
Needless Complexity
A design smells of needless complexity when it contains elements that aren't currently useful.
This frequently happens when developers anticipate changes to the requirements and put
facilities in the software to deal with those potential changes.
By preparing for many contingencies, the design becomes littered with constructs that are never
used and meanwhile, the design carries the weight of these unused design elements. This makes
the software complex and difficult to understand.
Needless Repetition
Cut and paste may be useful text-editing operations, but they can be disastrous code-editing
operations.
When the same code appears over and over again, in slightly different forms, the developers are
missing an abstraction.
When there is redundant code in the system, the job of changing the system can become difficult.
Bugs found in such a repeating unit have to be fixed in every repetition. However, since each
repetition is slightly different from every other, the fix is not always the same.
Opacity
Code can be written in a clear and expressive manner, or it can be written in an opaque and
convoluted manner.
Code that evolves over time tends to become more and more opaque with age.
A constant effort to keep the code clear and expressive is required in order to keep opacity to a
minimum.
This principle was first described by Tom DeMarco and Meilir Page-Jones.
They called it Cohesion (Interconnection), which they defined as the functional relatedness for
the elements of a module.
If a module has more than one responsibility, the responsibilities become coupled (united).
Changes to one responsibility may impair or inhibit the class's ability to meet the others. This
kind of coupling leads to fragile (delicate) designs that break in unexpected ways when changed.
For example, consider the design shown in the above Figure. The Rectangle class has two
methods, one draws the rectangle on the screen and the other computes the area of the rectangle.
Two different applications use the Rectangle class. One application does computational
geometry. Using Rectangle to help it with the mathematics of geometric shapes but never
drawing the rectangle on the screen. The other application is graphical in nature and may also do
some computational geometry, but it definitely draws the rectangle on the screen.
This design violates SRP. The Rectangle class has two responsibilities. The first responsibility is
to provide a mathematical model of the geometry of a rectangle. The second responsibility is to
render the rectangle on a GUI.
The violation of SRP causes several nasty problems. First, we must include GUI in the
computational geometry application. In .NET, the GUI assembly would have to be built and
deployed with the computational geometry application.
Second, if a change to the Graphical Application causes the Rectangle to change for some
reason, that change may force us to rebuild, retest, and redeploy the Computational Geometry
Application. If we forget to do this, that application may break in unpredictable ways.
A better design is to separate the two responsibilities into two completely different classes, as
shown in the below figure. This design moves the computational portions of Rectangle into the
Geometric Rectangle class. Now changes made to the way rectangles are rendered cannot affect
the computational geometry application.
The Single-Responsibility Principle is one of the simplest of the principles but one of the most
difficult to get right. Joining responsibilities is something that we do naturally, but finding and
separating those responsibilities is much of what software design is really about.
This principle was first described by Bertrand Meyer in the year 1988.
When a single change made to a program results in a cascade of changes to dependent modules,
then the design smells of Rigidity and Fragility.
Open Closed Principle advises us to refactor the system so that further changes of that kind will
not cause more modifications.
Modules that conform to Open Closed Principle have Two Primary Attributes.
As the requirements of the application change, we can extend the module with
new behaviors that satisfy those changes. In other words, we are able to change
what the module does.
Extending the behavior of a module does not result in changes to the source, or
binary, code of the module.
The binary executable version of the module whether in a linkable library, a DLL,
(or) a .EXE file remains untouched.
These two attributes are the most common ways of satisfying Open Closed Principle. They
represent a clear separation of generic functionality from the detailed implementation of that
functionality.
The above example figure shows a simple design that does not follow to Open Closed Principle.
Both the Client and Server objects are rigid. The Client object uses the Server object. Client
Object is Open for Extension but if any changes made by the Client object that will directly
modify the files that are present in the server object. Hence the second primary attribute of Open
Closed Principle fails.
The above example shows the corresponding design that follows to the Open Closed Principle by
using the STRATEGY pattern.
In this case, the client object is extended by creating new Client Interface object. The Client
object uses client interface object, so if any changes made by the Client object that will directly
modify the files that are present in the client interface object for temporarily.
However, the files that are present in the server object will not be modified. Hence, if the Client
objects wants to use a different server objects, a new derivative of the Client Interface object can
be created. The Client object and Server object can remain unchanged.
The Open Closed Principle is at the heart of object-oriented design. Conformance to this
principle is what yields the greatest benefits claimed for object-oriented technology – Flexibility.
Developers need to apply changes only to those parts of the program or design that exhibit
frequent changes.
This principle was first described by Barbara Liskov in the year 1988.
Liskov Substitution Principle Eliminates one of the design smell Needless Complexity.
A typical example that violates Liskov Substitution Principle is a Square object that derives from
a Rectangle object.
The Square object always assumes that the width is equal with the height. If a Square object is
used in a context where a Rectangle object is expected, unexpected behavior may occur because
the dimensions of a Square cannot be modified independently.
When considering whether a particular design is appropriate, one cannot simply view the
solution in isolation. One must view it in terms of the reasonable assumptions made by the users
of that Design.
Liskov Substitution Principle can not be practiced without careful and precise documentation of
object behavior.
High-level modules that contain the important policy decisions and business models of an
application. When these high level modules depend on the lower-level modules, changes to the
lower-level modules can have direct effects on the higher-level modules and can force them to
change in turn.
When high-level modules depend on low-level modules, it becomes very difficult to reuse those
high-level modules in different contexts. However, when the high-level modules are independent
of the low-level modules, the high level modules can be reused quite simply.
The above figure shows the conventional application architecture, lower-level components are
designed to be consumed by higher-level components which enable increasingly complex
systems to be built.
The goal of the dependency inversion pattern is to avoid this highly coupled distribution with the
mediation of an abstract layer, and to increase the re-usability of higher/policy layers.
The above figure shows the addition of an abstract layer, both high and lower-level layers which
reduce the traditional dependencies from top to bottom. Nevertheless, the ″inversion″ concept
does not mean that lower-level layers depend on higher-level layers. Both layers should depend
on abstract interfaces that draw the behavior needed by higher-level layers.
In a direct application of dependency inversion, the abstract interfaces are owned by the
upper/policy layers. This architecture groups the higher/policy components and the abstract
interfaces that define lower services together in the same package. The lower-level layers are
created by inheritance of these abstract interfaces.
The inversion of the dependencies and ownership encourages the re-usability of the higher/policy
layers. Upper layers could use other implementations of the lower services when the lower-level
layer components are closed or when the application requires the reuse of existing services.
The principle of dependency inversion is the fundamental low-level mechanism behind many of
the benefits claimed for object-oriented technology. Its proper application is necessary for the
creation of reusable frameworks.
This principle was first described by Martin Robert in the year 2002.
ISP splits interfaces that are very large into smaller and more specific ones so that clients will
only have to know about the methods that are of interest to them. Such shrunken interfaces are
also called Role Interfaces.
Let's consider a slightly more significant example: the traditional Automated Teller Machine
(ATM) problem.
The below figure shows the user interface of an ATM that needs to be very flexible. The output
may need to be translated into many different languages and it may need to be presented on a
screen, on a braille tablet, or spoken out a speech synthesizer.
Consider each transaction that the ATM can perform is encapsulated as a derivative of the object
transaction. Thus, we might have such objects as Deposit Transaction, Withdrawal Transaction,
transfer Transaction, and so on. Each of these objects invokes UI objects.
For example, the below figure shows in order to ask the user to enter the amount to be deposited,
the Deposit Transaction object invokes the Request Deposit Amount object of the UI class.
Likewise, in order to ask the user how much money to transfer between accounts, the transfer
Transaction object calls the Request Transfer Amount object of UI.
Each of the transactions is using UI objects which creates the possibility that changes to one of
the derivatives of Transaction will force corresponding change to UI, thereby affecting all the
other derivatives of transaction and every other objects that depends on the UI interface.
Something smells like rigidity and fragility around here.
Since Deposit Transaction, Withdrawal Transaction, and transfer Transaction all depend on the
UI interface, they are all likely to be rebuilt.
The below figure shows that coupling can be avoided by segregating the UI interface into
individual interfaces, such as Deposit UI, Withdraw UI, and Transfer UI. These separate
interfaces can then be multiply inherited into the final UI interface.
Each client-specific interface declares only those functions that its particular client or client
group invokes and this can be achieved by breaking the interface of the objects into many client-
specific interfaces.
time, addressing your greatest area of pain. Give it enough time for a fair trial and evaluate
the results. If it’s working for you, master that tool before you go on to the next area of pain
and the next tool. Multitasking might work for some situations, but new technology demands
full attention.
Vendor Tools :
Commercial tools are perceived as a safe bet. It’s hard to criticize someone for selecting a
well known tool that’s been around for years. They’re likely to come with manuals, support,
and training. For testers or other users who lack a technical background, the initial ramp-up
might be faster. Some are quite robust and feature-rich. Your company may already own one
and have a team of specialists who know how to use it.
VERSION CONTROL
Version control, also known as revision control or source control, Revision control manages
changes to a set of data over time
In computer software engineering, revision control is any kind of practice that tracks and
provides control over changes to source code. Software developers sometimes use revision
control software to maintain documentation and configuration files as well as source code.
As teams design, develop and deploy software, it is common for multiple versions of the
same software to be deployed in different sites and for the software's developers to be
working simultaneously on updates. Bugs or features of the software are often only present in
certain versions. Therefore, for the purposes of locating and fixing bugs, it is vitally important
to be able to retrieve and run different versions of the software to determine in which
version(s) the problem occurs.