Many problems on software development are due to
which I call technology driven design obsession. Don’t let technologies and
stacks dictate your design, keep it as simple as possible. Many developers try
to use new technologies on their projects (because they are cool :P or have
cool names like Marionette.Js I love that name) and forget about the business
value and what they are trying to achieve. Instead of focusing on the use case
and the goal of the application, they try to fit the problem to technology and
suddenly they become slaves to these tools.
Tuesday, December 11, 2012
Friday, August 17, 2012
Open / Close principle and Design Patterns
The open/ closed principle
represents the second principle of SOLID design,
in this post I will give an overview of this principle and how to achieve it
using different design patterns (including some notes about the limits of each
solution) then I will present a different way of achieving it using a less
known pattern which is the marker interface combined with some dependency injection and auto-wiring.
The open/closed principle can be summarized
by:
“Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.” Uncle Bob
As mentioned in an earlier post, good
software is a software that can be adapted to a change easily. Change in
requirement or functionality happen quiet often during the life of the software.
Its ability to change and adapt to fulfill the new requirements is the key for its success otherwise the cost of maintenance and support as time goes by can cause its death or even the death of the company (specially if it is a startup with limited resources).
The goal of this principle is to avoid cascading changes every time that we add a small change, making the chances to breaking existing code much smaller. Open for extension means that we
can change the behaviour and extend the functionality of the module. Close for modifications means
that the module can be changed but without touching the source code. At first look, this seems awkward,
how can we change the functionality without touching the code?
This can be achieved using some known behavioural
design patterns. I should note that it is hard to apply OCP at 100 % but at
least we can make our code extensible and resilient for a certain type of
changes, this depends on the context (TDD helps identifying these changes during the iterative process, more
on this in a later post dedicated to TDD and how/when to apply design patterns ).
Traditional solutions:
Strategy Pattern:
This pattern is well documented and well known, the main idea is to separate the abstract generic algorithm from its implementation this allows a decoupling between the functionality (behaviour) and the class that uses the behaviour. This way we can add more functionality by implementing the Strategy interface then tell the context to use it.
Notes and limitations:
-I have seen some examples in books where they implement a method in the context to choose the strategy to use, depending on the context, personally if the choice of the strategy is a configuration concern i try to avoid this way since it implies some changes to the context and it can lead to many if-else statements which i hate, as alternative i like to push this responsibility to IOC container like structure map since he is responsible for managing the creation and the life cycle of objects, this always depends on the context, for example if the selection of the right strategy depends on some internal processing inside the context then placing a method that choose the strategy inside the context makes sense but i always try to avoid if statements with some fashion :P).
-If the concrete strategies contains only one method they can be replaced by delegates instead of classes.
-I think we should pay attention when using Strategy pattern specially on how we select the strategy to use. If the selection is inside the context class and each time we add a strategy we must change the code in the context than it is still open for modification and breaks the OCP.
Visitor Pattern:
In short, the visitor pattern allows to add functionality to classes without modifying them by implementing a class (visitor) that contains different implementations of the desired functionality.
Notes and limitations:
-It is clear that the visitor pattern fits well to OCP but in my point of view it is against POO encapsulation primciple which consists in encapsulating data and methods manipulating that data in the same class, but it is a trade off between adding a method for each element every time we need to add a functionality to a hierarchy or just derive a class from the visitor.
- Another drawback is that we need to add a visit method for each derived visitor class each time we add an element, which means all classes will be open for modification each time we derive from Element.
There is other patterns that helps to apply OCP like decorator, chain of responsibility, ...
Summary
For this post i tried to focus more on the limitations and drwabacks of each pattern as i think it is essential in order to make a good use. Design patterns are not magic they should be well understood and used carefully otherwise it would result in an over-complicated software, i will dedicate a post on how to use design patterns, their relatioin with TDD process.
For the next post i will write about a less known solution but very powerful based on marker interface with DI and Pub/Sub pattern (my favourite solution).
Stay tuned :)
Thursday, August 9, 2012
D.R.Y principle and the Broken clock
This will be a short post, it is more like taking note of a thought that crossed my mind.
VS
Dry: Don't repeat yourself principle, a well known and preached principle.
We should pay attention how to apply "Dryness".
Depending on the context, for example the source code for create and update may be identical in many scenarios but at sometime the logic may change and they can be different, if you try to apply dry by trying to use the same code base for the two operations this can catch you later. they are the same by accident, but will likely vary by design later and should therefore not share code in common.
Remember: even a broken clock is right twice per day. (but it is still broken)
:)
Tuesday, July 24, 2012
General thoughts about TDD, BDD, SOLID and Agile
TDD
I still remember first time i heard about TDD, i was curious and a little suspicious;
my first thought was how spending time and money writing more code that doesn’t add functionality
to the product could be beneficial???
First answer I come up with to this question was reducing
maintenance cost, I mean it will cost probably more to create the product but
on the long run it will be advantageous and we will get a good ROI (return on
investment) but couldn’t we reduce the maintenance cost by usual unit tests? Aren’t
they enough? Unit tests (test after) are less expensive, why should we create
tests first which imply of course creating mocks, interfaces, fakes (which
costs more time and more money). To
answer these question I decided to give it a try in a pet project, I fired visual studio and I started (tried to start)
coding.
Simple Remind of TDD steps:
1/ Write test
2/ Test should fail
3/ Write code to make test pass
So the first step consists of writing a test that fails and
it should focus on one feature and suddenly I started thinking
differently, focusing only on the feature and the requirements, use cases, scenarios,
trying to isolate this feature, trying to define its responsibility then
define interfaces needed for mocking purposes and using IOC container and
dependency injection. Repeating the steps 2,3,4 made me realize the difference
between unit tests and the added value of TDD.
In fact doing TDD pushes the developer to focus on the
requirement, and to produce high quality code that respects many practices and
principles of good software design.
It pushes the developer to focus on the single responsibility
of the feature and develop only the functionality needed to pass the test
(avoiding YAGNI), using the mocks will force the design by contract
(interfaces) and, the step of refactoring is very important trying to keep your
code dry and probably using design patterns in order to make your tests pass
and more resilient to change as adding more feature, tests and changes will
affect precedent tests.
I think of TDD as way to automate producing a good code, maintainable
and resilient to change but of course it requires some discipline and writing good
tests as Roy Osherove said bad tests (specially false green tests) are
worse than no tests at all, at least with no tests you don’t assume your code
is correct.
TDD fits well with Agile since it is a repetitive and
incremental process that focuses on single feature at a time. Logically related
features can be grouped to represent the portion of the final product released
in each iteration.
BDD
After TDD I heard about BDD, at first look from a developer perspective
I found them similar
TDD
|
BDD
|
Arrange
|
Given
|
Act
|
When
|
Assert
|
Then
|
There
is no big changes, personally I found BDD useful for workflows and business
rules and process. It forces the developer to think about the functionality of the
code not the code itself.
I will try to explain the difference with an example:
Let's take, Crediting an account scenario
-In TDD it will result in writing a code that tests focuses
on the add operation rather than its context.
-In BDD it will result in a code to test crediting the
account though hiding the technical details about the implementation, it
focuses more on why the code is created and putting it in a context usually using
ubiquitous language that can be understood by stakeholders, QA and Devs .
This is why i said from a developer perspective there is no
difference but in workflows and complex
business operation having a lot of business rules BDD is more convenient.
Usually workflows define the business and can be represented by a state
machine. State machine can be represented by:
Given the actual state when an event happen then trigger action X and update state.
Also BDD can represent a living documentation describing business rules and processes.
This is a huge advantage especially in DDD and complex applications with
complex business rules. Greg Young have elaborated a simple testing framework
that gives this magnificent output (note that this output is a result of a whole
architecture and design decision (CQRS and ES) that made generating such
results easy) :
Creating
customer opens bill - Passed
Date
Is(2011, 10, 6)
When:
Create customer 'Northwind' with id 7
Expectations:
[Passed] Created customer 7 'Northwind'
[Passed] Opened bill 7/1 from 20111006
Imagine all the value you can get by this, developers can
understand easily what is going on, completely understandable by stakeholders that can sign the acceptance based on this output.
Even more, tests can be written by business team than passed to developers, BDD
frameworks like Specflow generate the corresponding code for unit tests and then developers code the functionality.
Summary
Even if TDD contains the word test on it, it is really
different from testing and unit testing, its goal is much more than ensuring regression,
it pushes developers to code better and produces good software. As a successor
BDD isn’t different from TDD it just abstract how functionality is coded and
focus on why code is created, making this understandable by different actors in
an agile Team. In the end it is important to master the art of unit testing and
avoid bad tests as they are worse than no tests at all.
Sunday, July 15, 2012
What is a good software ???
By googling this
question probably you will get this answer : it must be maintainable, flexible,
extensible, scalable, testable, modular, reusable, loosely coupled,…
Personally i define a
good software as a software that can be adapted to a change easily.
The change could be
of any kind, like change of environment and platform (portability), change of
the number of users, number of requests (scalable) and specially change in
functionality or requirement (flexible, maintainable)…
As developers we
have been always struggling to keep up to these changes specially when we are
limited in time and budget which puts us under stress and make our lives
miserable. Of course we can’t blame clients for changing their mind we always
knew that this will happen and management guys can’t explain how a change cost
more than rewriting everything from scratch.
In years many
experts have established practices, development processes, and software
development methodologies trying to solve this problem (TDD, Agile, SOLID,
design patterns(GOF), YAGNI, KISS, DRY(don’t repeat yourself…), used wisely
these practices can make our lives much better.
I will post about these different practices and show the relation between them and how they are used to get a good software.
Stay tuned.
I will post about these different practices and show the relation between them and how they are used to get a good software.
Stay tuned.
Friday, June 29, 2012
How to face the huge amount of changes in IT world (from a software developer perspective)
IT professionals,
specially developers how are we supposed to deal with this huge amount of
changes, new concepts, APIs, technologies… ???
The IT world is moving fast we should be open
minded to accept changes. For example the old debate around ASP webforms VS ASP
MVC or when Node.js came out many said that using javascript
in both client side and server side is out of question (I don’t like
programming in javascript either but it is not a reason to treat Node.js as a
crap before even trying it).
We as developers we should know that there is no magic
solution or silver bullet for everything, we should use the right tool
( i will use the word tool to represent concept, pattern, methodology, language,…) for the right job.
Simple example: personally I found Webforms more fitted to
administrative pages than MVC, and MVC more suited for internet applications
than Webforms. Node.Js is more suited for certain type of application like sending updates to user in real time (long-polling).
Even some design patterns may become useless over the time (depends on the context).
Let's take the repository
pattern as example, we can find this pattern everywhere but did we really need it ??
This pattern came
out before actual ORMs. ORMs are already based on this pattern so why adding
additional abstractions specially for reads operations (make a controller that
calls a data service layer that calls a repository data access object that
calls an ORM that generate an sql query). Note, that I’m not saying that the repository pattern is
useless but we should ask the question if it is really needed (e.g if it is
used only for data access and we don’t need change tracking we could use simple
solution like Massive instead of NH or EF with all the added overhead). This
leads as to the next point
2-Don’t follow blindly, always try to understand when to use a tool and more
importantly when not to use it:
Usually when a new tool* came out we found articles, blog
posts and demos(usually with trivial examples that mislead the community of
developers) showing how to use this tool and advantages of using this tool. But
we notice that it is hard to find when not to use this
tool (you should dig and have an objective critical mind). As I said
earlier, we should use the right tool for the right job, in order to do that we
should know when and when not to use it depending on the context.
3-Orchestrate altogether: how to use the right tool is
good, combining all the tools together to get the right result is better and
also harder. Sometimes the problem is not on the set of the tools or knowledge of
how to use the tools but the challenge is how to combine them. This story from
Udi Dahan (one of my favourite blogger) illustrate what i meant.
4-Understand the context: in short use the right tool for the right job within the right context, some tools that applies in situation or project X doesn't mean that it is true in another situation or project Y even if it may seem similar.
Another point, don't lie on assumptions specially for performance or concurrency problems. For example, you may use every optimization technique that you are aware of to reduce response time but the only way to be sure of that is by testing it and doing a stress test. (just because that is an optimization technique that worked for another project doesn't necessarily mean that it will optimize your current one at least you can't be 100% sure of it).
That is it for this post probably there is more but these are the main advices that i have in mind now and that i think that are the most important to face the huge amount of innovations on the IT world.
Wednesday, June 27, 2012
Applying design patterns to SOLID design. Keep an eye on KISS and YAGNI !!! Part 1
I will start writing a series of articles about S.O.L.I.D design
and how to achieve it by using design patterns, I will not only focus on theory
but I will give some examples and code to try to explain the problem that each
principle of SOLID design is trying to solve and how to implement the solution
using design patterns.
I have noticed that the problem with design patterns is not
to understand them but most importantly when and how to use them in order to get a low coupled maintainable
and reusable software. Many programmers (not only juniors) use design patterns
just to use them because of the buzz words around them and because they have
been told that it is a good practice to use them. But like any good practice if
it is misused or/and misunderstood will cause problems instead of resolving them.
In case of misusing design patterns usually we end up with a more complex and
over engineered solution, this conducts us to two other software design
principles that we should be aware of, KISS and YAGNI.
YAGNI
acronym for” You Are Not Gonna Need It”, usually applying the solid design principle
and the use of design patterns means adding levels of abstractions and complex
objects. Using the right pattern for the right job is important, otherwise we
will end up with an over enginnered solution hard to understand and maintain
with more lines of code and of course more bugs.
KISS: “Keep it simple stupid” always simple solutions are
the best one don’t over complicate things by doing too much or an infinite loop
of “what if”.
That is enough for today i will develop more these principles and give some code examples in a later posts where i will show how to apply all these principles within a TDD process.
To be continued .... ;)