Agile FAQs
  About   Slides   Home  

 
Managed Chaos
Naresh Jain's Random Thoughts on Software Development and Adventure Sports
     
`
 
RSS Feed
Recent Thoughts
Tags
Recent Comments

Archive for the ‘Design’ Category

A Bird in the Hand is Worth Two in the Bush

Saturday, August 1st, 2015

In software world we call this speculative generality or YAGNI or over engineering.

IMHO we should not be afraid to throw parts of your system out every 6-8 months and rebuild it. Speed and Simplicity trumps everything! Also in 6-8 months, new technology, your improved experience, better clarity, etc. will help you design a better solution than what you can design today.

Just to be clear, I’m not suggesting that we do a sloppy job and rewrite the system because of sloppiness. I’m recommending, let’s solve today’s problem in the simplest, cleanest and most effective/efficient way. Let’s not pretend to know the future and build things based on that, because none of us know what the future looks like. Best we can do is guess the future, and we humans are not very good at it.

Embracing Simplicity to Kill Conditional Complexity – A Real World Example

Monday, October 28th, 2013

In the Agile India Submission system, we had a feature which would accept different url path to show matching proposals.

For example:
http://present.agileindia.org/agile-india-2014/agile-lifecycle/45_mins –> will return all 45 mins proposals under the Agile-Lifecycle track for the Agile India 2014 Conference.
http://present.agileindia.org/agile-india-2014/beyond-agile/90_mins –> will return all 90 mins proposals under the Beyond-Agile track for the Agile India 2014 Conference.

If we remove the last part .i.e. http://present.agileindia.org/agile-india-2014/agile-lifecycle –> will return all proposals under the Agile-Lifecycle track for the Agile India 2014 Conference.
and http://present.agileindia.org/agile-india-2014 –> will return all proposals for the Agile India 2014 Conference (could be other conferences as well.)

To achieve this, we had the following routes defined:

//URL Path = /agile-india-2014
app\get("/{conference}", function($req) {
    $query_params = structure_request_params($req['matches']);
    ...
});
 
//URL Path = /agile-india-2014/agile-lifecycle
app\get("/{conference}/{track}", function($req) {
    $query_params = structure_request_params($req['matches']);
    ...
});
 
//URL Path = /agile-india-2014/agile-lifecycle/45_mins
app\get("/{conference}/{track}/{label}", function($req) {
    $query_params = structure_request_params($req['matches']);
    ...
});

In our database we had the following:

CREATE TABLE `conference` (
  `key` VARCHAR(255) NOT NULL,
   ...
  PRIMARY KEY  (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
CREATE TABLE `track` (
  `conference` VARCHAR(255) NOT NULL,
  `key` VARCHAR(255) NOT NULL,
  ...
  PRIMARY KEY  (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
 
CREATE TABLE `label` (
  `conference` VARCHAR(255) NOT NULL,
  `track` VARCHAR(255) NOT NULL,
  `key` VARCHAR(255) NOT NULL,
  ...
  PRIMARY KEY  (`conference`,`track`,`key`)
) ENGINE= InnoDB DEFAULT CHARSET=utf8;
 
INSERT INTO `conference` VALUES ('agile-india-2014', ...);
INSERT INTO `track` VALUES ('agile-india-2014', 'agile-lifecycle', ...);
INSERT INTO `label` VALUES ('agile-india-2014', 'agile-lifecycle', '45_mins', ...);

And some really complicated logic:

// For example URL Path /agile-india-2014 will result in 
// $req_params = array('conference'=>'agile-india-2014')
// And URL Path /agile-india-2014/agile-lifecycle will result in 
// $req_params = array('conference'=>'agile-india-2014', 'track'=>'agile-lifecycle')
// And URL Path /agile-india-2014/agile-lifecycle/45_mins will result in 
// $req_params = array('conference'=>'agile-india-2014', 'track'=>'agile-lifecycle', 'label'=>'45_mins')
function structure_request_params($req_params){
    $query_params = array();
    if(isset($req_params['label'])){
        if(Conference::exists($req_params['conference'])){
            $query_params['conference'] = $req_params['conference'];
            if(Track::exists(array('conference' => $req_params['conference'], 'key' => $req_params['track']))){
                $query_params['track'] = $req_params['track'];
                if(Label::exists(array(
                                       'conference' => $req_params['conference'], 
                                       'track' => $req_params['track'], 
                                       'key' => $req_params['label'])
                                       )) {
                    $query_params['label'] = $req_params['label'];
                }
                else{
                    $query_params['search_term'] = array($req_params['label']);
                }
            }
            else{
                $query_params['search_term'] = array($req_params['track'], $req_params['label']);
            }
        }
        else{
            $query_params['search_term'] = array($req_params['conference'], $req_params['track'], $req_params['label']);
        }
    }
    else{
        if(isset($req_params['track'])){
            if(Conference::exists($req_params['conference'])){
                $query_params['conference'] = $req_params['conference'];
                if(Track::exists(array('conference' => $req_params['conference'], 'key' => $req_params['track']))){
                    $query_params['track'] = $req_params['track'];
                }
                else{
                    $query_params['search_term'] = array($req_params['track']);
                }
            }
            else{
                if(Track::exists(array('key' => $req_params['conference']))){
                    $query_params['track'] = $req_params['conference'];
                    if(Label::exists(array('track' => $req_params['conference'], 'key' => $req_params['track']))){
                        $query_params['label'] = $req_params['track'];
                    }
                    else{
                        $query_params['search_term'] = array($req_params['track']);
                    }
                }
                else{
                    $query_params['search_term'] = array($req_params['conference'], $req_params['track']);
                }
            }
        }
        else{
            if(isset($req_params['conference'])){
                if(Conference::exists($req_params['conference'])){
                    $query_params['conference'] = $req_params['conference'];
                }
                elseif(Track::exists(array('key' => $req_params['conference']))){
                    $query_params['track'] = $req_params['conference'];
                }
                elseif(Label::exists(array('key' => $req_params['conference']))){
                    $query_params['label'] = $req_params['conference'];
                }
                else{
                    $query_params['search_term'] = array($req_params['conference']);
                }
            }
        }
    }
    return $query_params;
}

And supporting model classes:

class Conference{
    static function exists($conference){
        DB::query('SELECT * FROM conference WHERE conference.key = %s', $conference);
        return (DB::count() > 0);
    }
}
 
class Track{
    static function exists($query_params){
        $search_query = Track::create_search_query($query_params);
        DB::query("SELECT * FROM track WHERE $search_query");
        return (DB::count() > 0);
    } 
 
	private static function create_search_query($query_params){
        $search_query = array();
        foreach($query_params as $key => $value){
            $search_query[] = "$key='$value'";
        }
        return join(' AND ', $search_query);
    }
}
 
class Label{
    static function exists($query_params){
        $search_query = Label::create_search_query($query_params);
        DB::query("SELECT * FROM label WHERE $search_query");
        return (DB::count() > 0);
    }
 
	private static function create_search_query($query_params){
        $search_query = array();
        if(!empty($query_params)){
            foreach($query_params as $key => $value){
                $search_query[] = "$key='$value'";
            }
            return join(' AND ', $search_query);
        }
        return '';
    }
}

This was extremely hard to understand, so I decided to clean it up and get rid of the conditional complexity code smell.

Refactored code:

function structure_request_params($req_params){
    $criteria = array('conference', 'track', 'label');
    $params = array_values($req_params);
    return build_search_query_params($criteria, $params, array());
}
 
function build_search_query_params($criteria, $params, $results) {
    if(empty($params)) return $results;
    if(empty($criteria)) {
        if(!empty($params)) {
            $results['search_term'] = $params;
        }
        return $results;
    }
    if(is_present_in_db($criteria[0], $params[0])) {
        $results[$criteria[0]] = $params[0];
        array_shift($params);
    }
    array_shift($criteria);
    return map_criteria_params($criteria, $params, $results);
}
 
function is_present_in_db($table_name, $value){
    return (DB::queryFirstField("SELECT count(*) FROM $table_name WHERE `key` = %s", $value) > 0);
}

Also with this, we were able to delete the Model classes as they were not required.

Problem Solving Techniques For Evolutionary Design

Thursday, October 10th, 2013

At the Agile Goa conference, I ran a small workshop to help participants understand the core techniques one should master to effectively practice evolutionary design while solving real world problems.

Key take away:

  1. Eliminate Noise – Distill down the crux of the problem
  2. Add constraints to future simplify the problem
  3. Focus on one scenario at a time & incrementally build your solution
  4. Refactor: Pause, look for a much simpler alternative
  5. Be ready to throw away your solution & start again

Avatars of Test Driven Development (TDD)

Tuesday, March 19th, 2013

It’s easy to speak of test-driven development as if it were a single method, but there are several ways to approach it. In my experience, different approaches lead to quite different solutions.

In this hands-on workshop, with the help of some concrete examples, I’ll demonstrate the different styles and more importantly what goes into the moment of decision when a test is written? And why TDDers make certain choices. The objective of the session is not to decide which approach is best, rather to highlight various different approaches/styles of practicing test-driven development.

By the end of this session, you will understand how TTDers break down a problem before trying to solve it. Also you’ll be exposed to various strategies or techniques used by TDDers to help them write the first few tests.

Outside In – Behaviour Driven Development (BDD)

Tuesday, March 19th, 2013

Recently at the Agile India 2013 Conference I ran an introductory workshop on Behavior Driven Development. This workshop offered a comprehensive, hands-on introduction to behavior driven development via an interactive-demo.

Over the past decade, eXtreme Programming practices like Test-Driven Development (TDD) and Behaviour Driven Development (BDD) have fundamentally changed software development processes and inherently how engineers work. Practitioners claim that it has helped them significantly improve their collaboration with business, development speed, design & code quality and responsiveness to changing requirements. Software professionals across the board, from Internet startups to medical device companies to space research organizations, today have embraced these practices.

This workshop explores the foundations of TDD & BDD with the help of various patterns, strategies, tools and techniques.

Test Driven Development Applied Workshop by Lasse Koskela at Agile India 2013

Monday, January 14th, 2013

Lasse Koskela will be presenting a workshop on ‘Test Driven Development Applied’ at Agile India 2013. He works as a coach, trainer, consultant and programmer, spending his days helping clients and colleagues at Reaktor create successful software products.

Lasse Koskela

Lasse is also the author of books ‘Practical TDD and Acceptance TDD for Java Developers’ and ‘Effective Unit Testing’.

He is one of the pioneers of the Finnish agile community and speaks frequently at international conferences. He recently spoke at Agile2012.

We interviewed Lasse recently and asked him several questions related to one of his favourite topics TDD (Test Driven Development).

What are the mindset changes required by the developer(s) and team members when adopting TDD?

That would likely depend on the developer but I’d say that most often the biggest change required in one’s mindset is to acknowledge that you don’t know everything.

The more experience a programmer has the more likely they are to think of themselves as being “good”. A little confidence can be a huge boon to productivity but too much confidence creates blind spots–we literally learn to not question our assumptions and end up repeating the same old solution even if it’s not a very good fit.

TDD, on the other hand, makes us state some of those assumptions–such as what would be a good design for this class–in such concrete terms that it’s difficult to ignore the awkwardness when the same old solution doesn’t quite fit. It doesn’t fit and you can feel it through the difficulty you’re having writing a test for that design. Sometimes, you look at your test and go, “that doesn’t make any sense–much easier would be to…” And you end up changing the design.

How does TDD help developers in improving the art of software craftsmanship?

The process of programming test-first where you begin by expressing your intent from an automated unit test’s perspective has an almost magical effect on the kind of code you write. It’s much harder to write the kind of monolithic code we’ve all come to hate so much because the process of test-code-refactor invites you to create small, composable classes with clear responsibilities.

What I’ve also found is that TDD tends to help programmers learn what object-oriented design really means. It’s not just about encapsulating your code into “classes” but it’s about putting cohesive behavior into those classes. I wouldn’t go as far as saying that TDD makes you write object-oriented code but it certainly helps. I would say, however, that the better you understand object-oriented design the more comfortable you’ll likely feel test-driving code.

TDD is often perceived as slow, how does one justify the costs and benefits of TDD?

I haven’t heard that particular comment in a while but there certainly are a lot of skeptics when it comes to TDD. I guess every significant programming technique will have some skeptics. Skepticism is not a bad thing per se. In reasonable amounts a little skepticism is a healthy thing to have. That’s why I don’t try to persuade people to believe that TDD is good for them. I might believe but that doesn’t matter much. What matters is whether they themselves have an aspiration for becoming better. If you have that aspiration, perhaps you’ll give TDD a try and see for yourself.

With that said, there has been quite a lot of research into TDD–much more than around most other agile engineering practices–and that research seems to support the notion that TDD is a viable method for developing software. Research done at IBM and Microsoft, for instance, has measured that TDD (compared to a test-last approach) reduced defect densities by 40-90% while the management estimated that it added 15-35% to the time to implement a feature. The management had also concluded that the cost was far outweighed by the time and cost savings created by the reduction of defects.

I will repeat, however, that I don’t want you to take my word for it–or the researchers’ for that matter (especially without reading the research papers yourself). Instead, I’d like people to accept the possibility that they may or may not experience those reported advantages. If they decide to give it a try, even better. If they don’t, I hope they’re giving some other new technique a try. The absolute worst outcome would be that we stagnate at the status quo and stop improving on our profession.

What will be the key take away for the workshop attendees?

For first-timers the key take away is absolutely the first-hand experience of test-driving code. For people who’ve already dipped their feet into the water, I would expect them to walk out with the realization that their style of programming test-first is just one of many–some of which they’ve seen applied in the workshop–and with a resolution to try something slightly different when they get back to work. That’s something I am hoping to take away myself, too!

Seats for Lasse’s workshop are limited so book soon to avoid disappointment: http://booking.agilefaqs.com

Top 25 Blog Posts from Naresh Jain in 2012

Saturday, January 5th, 2013

Following were the most read blogs in 2012 on Managed Chaos:

  1. Upstream Connection Time Out Error in Nginx
  2. Setting up Tomcat Cluster for Session Replication
  3. Inverting the Testing Pyramid
  4. Simple Design
  5. Cannot create JDBC driver of class ” for connect URL ‘null’
  6. IMEI Unlock: Downgrade iPhone 3Gs baseband to 5.13.04 from 6.15.00
  7. Could not inspect JDBC autocommit mode
  8. Goodbye Simplicity; I’m Object Obsessed
  9. Enabling Multicast on your MacOS (*Unix)
  10. How to move CVS repository without losing history?
  11. How to Access Raw HTTP Headers in Chrome?
  12. he Window of Opportunity Phenomenon
  13. Deliberate Practice: The Expressway to becoming an Expert
  14. Single Assert Per Unit Test: Myth
  15. Benefits of Behavior Driven Development (BDD)
  16. My Take on Services vs. Product Company
  17. OO Design Principles
  18. Naked Agile
  19. Hudson: Access Denied User is missing the Read permission
  20. Is your Scrum Master Effective?
  21. Importance of Unit Testing and Test Driven Development (TDD)
  22. Skills a good Product Owner should Master
  23. Story Points and Velocity: Recipe for Disaster
  24. Advantages of Part-time Coaching
  25. What Software Company should I join in India?

Benefits of Behavior Driven Development (BDD)

Sunday, November 11th, 2012

Should you consider BDD for your team? I just wanted to share my experience with BDD, which you could consider as food for thoughts:

  • Why? – How often does your development team ask the business team why certain feature is important? More importantly, why now and how much of it is enough? In my experience with BDD, the approach naturally lends the teams to have a constructive discussion about this. I’ve seen this leading to a genuine collaboration between business and development. In short, BDD helps getting the right people to discuss the right amount (depth) of things at the right time.
  • Better commitment and buy-in: BDD lays very heavy emphasis on Business value. It forces the Business to justify the priority by showing concrete value. Also it helps the development teams to embrace the prioritizes set by Business, because they understand the thinking process much better. Interestingly, I’ve noticed that teams that practice BDD, I rarely see either sides throwing their weight around to push their pet features through. Also due to the focus on value, rarely I find teams building useless feature for the sake of proving productivity.
  • Ubiquitous domain language: By working together, the business team & the development team build a shared understanding by using tools/techniques like product discovery, story maps, user stories, acceptance criteria and scenarios to create an ubiquitous domain language. The ubiquitous language is usable/understandable not only by domain experts, but also by every member of the team. This goes a long way in reducing the complexity in the domain and making the barrier-to-entry much lower for new members.
  • Right focus: BDD can help you focus on the user’s needs and the expected behavior instead of jumping ahead and getting caught up in implementation details upfront. Also I’ve seen teams which are new to Test Driven Development (TDD), seem to focus too much on “testing” missing the point. BDD helps the teams focus on system’s behavioral aspects rather than focusing on testing your implementation. Over the years, we’ve learned that up-front analysis, design, planning and test planning, all have a diminishing return. In my experience BDD helps strike the balance.
  • Evolutionary Design: Agile (eXtreme Programming in particular) has killed the notion of “fully-specified, completely-detailed-out requirements upfront.” It is a well accepted fact that we won’t be able to figure out all the requirements when we are starting off with a project. BDD, at its very crux, embraces the fact of evolving product understanding and hence helps your system’s design evolve to keep pace with the changing needs.
  • Breaking the knowledge silos in distributed team: Having worked with distributed teams for over a decade, due to the distributed nature, one common problem I see is domain knowledge gap between the team members. Esp. teams which are away from the real business, have a hard time understanding and questioning the business requirements. Usually there are gaps or misunderstanding, leading to rework and frustration. Even if your team is not distributed, you might be familiar with the problems of knowledge silos. I don’t think BDD alone solves this problem, but at least it encourage teams to work more closely and reduces the gap. It also encourages a generalizing specialist attitude in team members, helping with other eXtreme programing practices like pairing, collective ownership, etc.
  • Greater ROI: Behavior has a much longer shelf life than your implementation and implementation related documentation. Also as the business rules change, BDD captures it better than it being lost in documents and code.
  • Predictability & Confidence: Also in my experience working with teams using BDD, I see that they have much better (or at least feel they have better) predictability and confidence in their work.

What’s your experience?

Also to clarify, what I mean by Business team and Development team, my definitions below:

Business Team: Folks who focus on “Are we building the right product.” This usually includes the following roles: Product Owner/Manager, Stakeholders, Product Designer (User Experience), Subject Matter Expert, Business Analysts, and so on.

Development Team: Folks who focus on “Are we building the product right.” This usually includes the following roles: Architects, Tech Leads, Developers, Testers, Graphics designers, Database administrators and so on.

Goodbye Simplicity I’m Object Obsessed – Example

Saturday, July 14th, 2012

Suppose we had the following (utterly) simplistic requirement:

@Test
public void politiciansDontNeedToPayTax() {
    whenIncomeIs(10000).verify(POLITICIANS).pay(0);
}
 
@Test
public void residingAliensGetAwayByPayingLittleTax() {
    whenIncomeIs(10000).verify(ALIENS).pay(1000);
}
 
@Test
public void richPeopleArePunishedWithHighestTax() {
    whenIncomeIs(10000).verify(RICH_PEOPLE).pay(3000);
}

where:

TaxPayer RICH_PEOPLE = new RichPeople();
TaxPayer ALIENS = new ResidingAliens();
TaxPayer POLITICIANS = new Politicians();

To fullfil this requirement, we’ve the following code:

Tax Payer

Parent Class:

public abstract class TaxPayer {
    protected abstract double getTaxPercentage();
 
    public double calculateTaxAmount(final long income) {
        if (getTaxPercentage() == 0)
            return 0;
        return income * getTaxPercentage() / 100.0;
    }
}

Each child class:

public class Politicians extends TaxPayer {
    private double taxPercentage = 0;
 
    @Override
    protected double getTaxPercentage() {
        return taxPercentage;
    }
}
public class RichPeople extends TaxPayer {
    private final double taxPercentage = 30;
 
    @Override
    protected double getTaxPercentage() {
        return taxPercentage;
    }
}
public class ResidingAliens extends TaxPayer {
    private final double taxPercentage = 10;
 
    @Override
    protected double getTaxPercentage() {
        return taxPercentage;
    }
}

One would wonder what good are these child classes? Feels like a class explosion. Sure enough! This is the pathetic state of Object Oriented programming in many organizations, esp. the Enterprise software side of the world.

One could have easily used an enum to solve this problem:

Refactored Tax Payer

public enum TaxPayer {
    Politicians(0), Aliens(.1), RichPeople(.3);
 
    private double taxPercentage;
 
    private TaxPayer(double taxPercentage) {
        this.taxPercentage = taxPercentage;
    }
 
    public double calculateTaxAmount(final long income) {
        return income * taxPercentage;
    }
}

Stay away from Design Patterns; master Value, Principles and Basics Skills first

Thursday, June 7th, 2012

Unfortunately many developers think they already know enough values and principles, so its not worth spending anytime learning or practicing them. Instead they want to learn the holy grail of software design – “the design patterns.”

Values Principles and Patterns

While the developers might think, design patterns is the ultimate nirvana of designing, I would say, they really need to learn how to think in their paradigm plus internalize the values and principles first. I would suggest developers should focus on the basics for at least 6 months before going near patterns. Else they would gain a very superficial knowledge about the patterns, and won’t be able to appreciate its true value or applicability.

Any time I get a request for teaching OO design patterns, I insist that we start the workshop with a recap of the values and principles. Time and again, I find developers in the class agreeing that they are having a hard time thinking in Objects. Most developers are still very much programming in the procedural way. Trying to retrofit objects, but not really thinking in-terms of objects and responsibilities.

Recently a student in my class shared that:

I thought we were doing Object Oriented Programming, but clearly its a paradigm shift that we still need to make.

On the first day, I start the class with simple labs, in the first 4-5 labs, you can see the developers struggle to come up with a simple object-oriented solution for basic design problems. They end up with a very procedural solution:

  • main class with a bunch of static methods or
  • data holder classes with public accessors and other or/er classes pulling that data to do some logic.
  • very heavy use of if-else or switch

Its sad that teams don’t understand nor give importance to the following important OO concepts:

  • Data and Logic together – Encapsulation (Everyone knows the definition of encapsulation, but how to put it in proper use, is always a big question mark.) Many developers write public Getters/Setters or Accessors by default on their classes. And are shocked to realize that it breaks encapsulation.
  • Inheritance is the last option: It is quite common to see solutions where slight variation in data is modeled as a hierarchy of classes. The child classes have no behavior in them and often leads to a class explosion.
  • Composition over Inheritance – In various labs, developers go down the route of using Inheritance to reuse behavior instead of thinking of a composition based design. Sadly, inheritance based solutions have various flaws that the team can’t realize, until highlighted. Coming up with a good inheritance based design, when the parent is mutable, it extremely tricky.
  • Focus on smart data-structure: The developers have a tough time coming up with smart data-structure and putting logic around it. Via various labs, I try to demonstrate how designing smart data-structures can make their code extremely simple and minimalistic.

I’ve often noticed that, when you give developers a problem, they start off by drawing a flow chart, data-flow diagram or some other diagram which naturally lends them into a procedural design.

Thinking in terms of Objects requires thinking of objects and responsibilities, not so much in terms of flow. Its extremely important to understand the problem, distill it down to the crux by eliminating noise and then building a solution in an incremental fashion. Many developers have a misconception that a good designs has to be fully flushed out before you start. I’ve usually found that a good design emerges in an incremental fashion.

Even though many developers know the definition of high-cohesion, low-coupling and conceptual integrity, when asked to give a software or non-software example, they have a hard time. It goes to show that they don’t really understand the concept in action.

Developers might have read the bookish definition of the various Design Principles. But when asked to find out what design principles were violated in a sample design, they are not able to articulate. Also often you find a lot of misconception about the various principles. For example, Single Responsibility, few developers say that each method should do only one thing and a class should only have one responsibility. What does that actually mean? It turns out that SRP has to do more with temporal symmetry and change. Grouping behavior together from a change point of view.

Even though most developers raise their hands when asked if they know code smells, they have a tough time identifying them or avoiding them in their design. Developers need a lot of hands-on practice to recognize and avoid various code smells. Once you learn to recognize code smells, the next step is to learn how to effectively refactor away from them.

Often I find developers have the most expensive and jazzy tools & IDEs, but when you watch them code, they use their IDEs just as a text-editor. No automated refactoring. Most developers type “Public class xxx” instead of writing the caller code first and then using the IDE to generate the required skeleton code for them. Use of keyboard shortcuts is as rare as seeing solar eclipse. Pretty much most developers practice what I call mouse driven programming. In my experience, better use of IDE and Refactoring tools can give developers at least 5x productivity boost.

I hardly remember meeting a developer who said they don’t know how to unit test. Yet time and again, most developers in my class struggle to write good unit tests. Due to lack of familiarity or lack of practice or stupid misconceptions, most developers skip writing any automated unit tests. Instead they use Sysout/Console.out or other debugging mechanism to validate their logic. Getting better at their unit testing skills and then gradually TDD can really give them a productivity boost and improve their code quality.

I would be extremely happy if every development shop, invested 1 hour each week to organize a refactoring fest, design fest or a coding dojo for their developers to practice and hone their design skills. One can attend as many trainings as they want, but unless they deliberately practice and apply these techniques on job, it will not help.

    Licensed under
Creative Commons License