Click here to Skip to main content
Click here to Skip to main content

Learn How to Write Good Software

, 25 Sep 2013
Rate this:
Please Sign up or sign in to vote.
This article will guide you step by step to write good software every time.

Introduction

It has been a long period since I have been developing software for different clients. I always try my best to write good software that fulfills all the customer requirements and most importantly it satisfies me that I delivered a good work to the customer. I always try to define what good software means and how I can deliver good work every time. But the challenges and customer requirements are different for each client. The expectation level also varies from customer to customer.

It is never easy to figure out where to start a project and how to deliver software that satisfies the customer, developer, and architect. We have studied a lot about good software and programming, but while programming, most developers and architects ignore the rules and that puts them in trouble.

In this article we will study about what is good software and how we can apply Object Oriented Analysis and Design rules to write good software. We have studied about encapsulation, delegation, decoupling, and other object oriented practices, but how would we use them in actual programming?

What is good software?

It is a vague term to ask about it, because different people have different definitions and meanings for it.

Customer says good software does what the customer wants and if he uses it in a new way, it should still work and will not crash and give unexpected results. Mostly customers do not worry about the architecture and other best programming practices for developing the software. Instead he is more conscious about the result of the software that it is supposed to give. Crashing applications and weird results irritate customers and affects his confidence on programmers.

Object oriented programmer says good software is code written in an object oriented way, it does not duplicate code in it. Each object is responsible for handling its own behavior. Apply proper object oriented rules on your application to make it solid and easily extendable. Your structure should be more flexible for handling new changes.

Architect says good software is software in which you use proper tiers and design patterns. Your software has reusable components in it, because it is not better to solve the same problem over and over again. Your application is open for extension but closed for modifications. The components should be loosely coupled.

Quality assurance team says no software is good software because if they think software is good then how can they find bugs in it? It was a funny and interesting answer given to me by my colleague. But the thoughts of the customer and testing person are almost the same. Good software gives expected results and does not crash, and gives proper result if they want to use it in different ways. And most importantly it fulfills all the customer requirements.

The thoughts of others like project managers, MD, CM, and CEO etc., are almost the same and those are already being covered in the above definitions.

We have heard about good software from different people. How can we satisfy all these people when we deliver software? The answer is not easy at this stage, but you will learn in this article about good software and it will increase your brain power to deliver good software.

Mobile shop project

One of my friends has a mobile shop and he sells new and used mobile phones. He was managing his inventory manually on papers. One day he decided to throw out his paper based inventory system and wanted to use an automated system for his shop to manage his inventory and search functionality to help customers to select their dream mobile phone. He was moving to a new system because he wanted to increase his sales and manage his inventory. He gave the project to a renowned firm to build the automated system. After a few months the programming firm gave him a new computerized system that they built for him. Let’s see how the firm designed the new system for the mobile shop.

New application for mobile shop

The programming firm completely replaced the handwritten notes into a new system to search for a mobile for customers. They gave this UML class diagram to show what they did.

They created two classes: Mobile that contains information of the device, and Inventory that contains all the devices and methods for add, search, and get mobile.

Let’s have a look at the actual code written by the programming firm.

Mobile code

The Mobile class as it is depicted in the UML diagram contains all the properties for the mobile device and it has a constructor which takes all the data while creating the object and it only exposes the getter method of the property.

public class Mobile
{
    private string _iemi;
    private double _price;
    private string _brand;
    private string _model;
    private string _color;

    public Mobile(string ieme, double price, string brand, string model, string color)
    {
        _iemi = ieme;
        _price = price;
        _brand = brand;
        _model = model;
        _color = color;
    }

    public string IEMI{ get{ return _iemi; } }

    public double Price{ get{ return _price; } }

    public string Brand{ get{ return _brand; } }

    public string Model{ get{ return _model; } }

    public string Color{ get { return _color; } }
}

Inventory code

The Inventory class contains the list of all the mobiles and exposes methods to add mobile, get mobile, and search mobile.

public class Inventory
{
    List<mobile> _mobiles = new List<mobile>();

    public void AddMobile(string ieme, double price, string brand, string model, string color)
    {
        var mobile = new Mobile(ieme, price, brand, model, color);
        _mobiles.Add(mobile);
    }

    public Mobile GetMobile(string ieme)
    {
        foreach (var mobile in _mobiles)
        {
            if (mobile.IEMI == ieme)
            {
                return mobile;
            }
        }
        return null;
    }

    public Mobile SearchMobile(Mobile mobile)
    {
        foreach (var m in _mobiles)
        {
            if (!string.IsNullOrEmpty(mobile.Brand) && mobile.Brand != m.Brand)
                continue;
            if (!string.IsNullOrEmpty(mobile.Model) && mobile.Model != m.Model)
                continue;
            if (!string.IsNullOrEmpty(mobile.Color) && mobile.Color != m.Color)
                continue;
            return m;
        }
        return null;
    }
}

The SearchMobile method that will be used in our further discussion later in this article is the most important method for the mobile shop because the customer app will use it to find mobiles for customers. Customer can perform search on brand, model, and color. This method contains the logic for comparing first suitable device for the search.

Software is having search issue

When the mobile shop started using the new computerized system for searching for mobiles, sometimes the search system did not return any results but the shopkeeper knew he had devices in his stock. So he started losing his customers because of the weird results of the system.

The software delivered by the programming firm could not satisfy the customer and he comes back to them with complaints. So the software delivered by the programming firm is not a good software.

How can we deliver good software every time?

The question arises in the mind how can we write good software every time. Is there any set of rules by following which we can write good software? Read the definition of the customer, programmer, and architect again and try to define a set of rules for good software. A good software must satisfy the customer, it must have object oriented programming prionciples applied on it, and it should be loosely coupled. We can break the definition of good software in three steps.

Keeping the view of different people in our mind we figure out these three main steps to write a good software. Now we will apply these three on the mobile shop project to write good software.

Software does what customer wants

The project delivered by the programming firm does not satisfy the customer. They sit together and start finding the reasons of the broken search. When they analyzed and test the application by writing a test tool they come to know that the issue is because of the letter casing. The search module matches the product in a case sensitive way. E.g., Mobile shop has “Nokia” in his inventory and customer is searching device using the string “nokia”.

They start a discussion on the different solutions. One developer says just fixing the issue and delivering it again and not to worry about the design yet. Another says we cannot deliver the project that causes some other problems again, so we must be smart enough to fix the issue with a better design.

They all agreed on the “Don’t create a problem to solve problem”. It is the smart and right way to do and handle things. They finalized the following solution for the problem.

  1. Every string comparison should use ToLower to avoid the problem the next time.
  2. Use a constant or enum for a fixed range of values to avoid misspellings and case issues.

First improvement in the software

The first improvement they did in the software to avoid the string comparison issue was adding ToLower() in the compare statement and using the enum for the color.

The new Search method contains string comparison in lower case and also uses enums where required.

public Mobile SearchMobile(Mobile mobile)
{
    foreach (var m in _mobiles)
    {
        if (!string.IsNullOrEmpty(mobile.Brand) && mobile.Brand.ToLower() != m.Brand.ToLower())
            continue;

        if (!string.IsNullOrEmpty(mobile.Model) && mobile.Model.ToLower() != m.Model.ToLower())
            continue;

        if (mobile.Color !=  MobileColor.None && mobile.Color != m.Color)
            continue;

        return m;
    }
    return null;
}

The new search is solid and now it is working at it is supposed to. Customer is happy now, so at this stage we have completed our first task "Software does what the customer wants". After a few days the mobile shop thought, the application should return all the mobiles that match the search criteria. With this new enhancement he can increase his sale and give the customer the choice to pick a suitable device for him from multiple ones.

He comes up with a new requirement for his application. The search tool must return all mobiles that match the search criteria. The programming firm easily puts that logic in it.

public List<mobile> SearchMobile(Mobile mobile)
{
    List<mobile> toReturn = new List<mobile>();

    foreach (var m in _mobiles)
    {

        if (!string.IsNullOrEmpty(mobile.Brand) && mobile.Brand.ToLower() != m.Brand.ToLower())
            continue;

        if (!string.IsNullOrEmpty(mobile.Model) && mobile.Model.ToLower() != m.Model.ToLower())
            continue;

        if (mobile.Color != MobileColor.None && mobile.Color != m.Color)
            continue;

        toReturn.Add(m);
    }
    return toReturn;
}

The programming firm delivers the software with very small effort and that makes the customer very happy, because it is behaving exactly the way he wants it to. It increases sales and he is satisfied with the software now.

Now the software is behaving as it is supposed to. So our first task is achieved.

Try to apply some Object Oriented Principles

The customer is happy and the software is doing what it is supposed to. Now let’s try to apply some OO principles to add some flexibility to handle new changes. When the programming firm starts looking, they notice that the search is taking Mobile as a parameter, but it does not use IEMI and Price for filtering records. That means there is something wrong with the design and we have to rethink about it for improvements.

They come up with the new solution. The mobile object is not doing what its name suggests. And it is also not representing a single concept. Let’s try to remove extra properties that do not directly belong to mobile. We create a new class MobileSpec and add all those properties in it that are related to the specification. The new UML of the system is given below.

After applying some basic object oriented concepts the code is much clear now, it looks a bit flexible. The new Mobile class is now this:

public class Mobile
{
    private string _iemi;
    private double _price;
    private MobileSpec _mobileSpec;

    public Mobile(string ieme, double price, string brand, string model, MobileColor color)
    {
        _iemi = ieme;
        _price = price;
        _mobileSpec = new MobileSpec( brand, model, color);
    }

    public string IEMI{ get{ return _iemi; } }
    public double Price{ get{ return _price; } }
    public MobileSpec Spec{ get{ return _mobileSpec; } }
}

The search is also much cleaner now.

public List<mobile> SearchMobile(MobileSpec mobileSpec)
{
    List<mobile> toReturn = new List<mobile>();

    foreach (var m in _mobiles)
    {

        var specs = m.Spec;

        if (!string.IsNullOrEmpty(mobileSpec.Brand) && 
                   mobileSpec.Brand.ToLower() != specs.Brand.ToLower())
            continue;

        if (!string.IsNullOrEmpty(mobileSpec.Model) && 
                   mobileSpec.Model.ToLower() != specs.Model.ToLower())
            continue;

        if (mobileSpec.Color != MobileColor.None && mobileSpec.Color != specs.Color)
            continue;

        toReturn.Add(m);
    }
    return toReturn;
}

Now just compare the new code with the old one. You will notice that the after applying some basic OOP rules the new code is well designed and more flexible.

Reusable and loosely coupled components

After a few months the customer comes back to the programming firm and asks him to add some extra fields for the mobile. Because now there are varieties of smart phones in the market, they have internal memory, screen resolution, and operating systems.

The programming firm takes it up for an amendment and starts thinking of adding these new fields in the MobileSpec file. But certainly they notice that the change is required in three classes in different areas.

  1. Add fields in the MobileSpec file.
  2. Add parameters on the Constructor of the Mobile class and also pass these parameters to MobileSpec in the code.
  3. In the Search method of the Inventory class add new fields for compression. And change the Add method of the Inventory class.

Is it a good design?

Good software has reusable components and it is open for extension and closed for modifications. But the existing structure of the Mobile project does not have both features in it. It is means whenever we add a new specification in the MobileSpec class, we will need to change all other classes again. It is a mess.

How can we make it loosely coupled? Each class should do its duty by itself and the other classes should not do work on behalf of any class. Observe the code of the Search method in the Inventory class. It is comparing the MobileSpec object in it. That means whenever we change the MobileSpec class, we will need to change the Search method. So our design is tightly coupled.

The first thing we do, they remove the MobileSpecs comparison from the Inventory class and write a new method Equal in the MobileSpec class and put all the comparison logic in the method.

public class MobileSpec
{    
    public bool IsEqual(MobileSpec mobileSpec)
    {
        if (!string.IsNullOrEmpty(mobileSpec.Brand) && mobileSpec.Brand.ToLower() != Brand.ToLower())
            return false;

        if (!string.IsNullOrEmpty(mobileSpec.Model) && mobileSpec.Model.ToLower() != Model.ToLower())
            return false;

        if (mobileSpec.Color != MobileColor.None && mobileSpec.Color != Color)
            return false;

        return true;

    }
}

The Search method in the Inventory class is much cleaner and it is not doing any extra work that is the responsibility of the MobileSpec class. Changes in MobileSpec will not affect the Search method of the Inventory class.

public class Inventory
{
    .
    .
    .

    public List<mobile> SearchMobile(MobileSpec mobileSpec)
    {
        List<mobile> toReturn = new List<mobile>();

        foreach (var m in _mobiles)
        {

            if (m.Spec.IsEqual(mobileSpec))
            {
                toReturn.Add(m);
            }
        }

        return toReturn;

    }
}

Now they think there is no need to take a separate parameter for the MobileSpec class in the constructor of the Mobile class. Simply take MobileSpec as a parameter to remove the dependency and to make the design as loosely coupled as possible.

public class Mobile
{

    private string _iemi;
    private double _price;
    private MobileSpec _mobileSpec;

    public Mobile(string ieme, double price,MobileSpec spec)
    {
        
        _iemi = ieme;
        _price = price;
        _mobileSpec = spec;
      
    }
    .
    .
    .
    .
}

With this change the AddMobile method of the Inventory class will also change. Also pass MobileSpec as a parameter here.

public void AddMobile(string ieme, double price,MobileSpec spec)
{
    var mobile = new Mobile(ieme, price, spec);
    _mobiles.Add(mobile);
}

Now if you look into the solution, the design is flexible and reusable. You can use the MobileSpec class independently and it has encapsulated all its properties and methods. The design has a loosely coupled component and changes in the Mobile class will not affect the other classes.

Now let’s add new fields in the MobileSpec class. You will notice that there will be no change required for other classes. You just need to add new fields, properties, and comparison statements in the IsEqual method.

public class MobileSpec
{
    private string _brand;
    private string _model;
    private MobileColor _color;
    private int? _internalMemory;
    private string _operatingSystem;
   

    public MobileSpec(string brand, string model, MobileColor color)
        : this(brand, model, color, null, "")
    {
    }

    public MobileSpec(string brand, string model, MobileColor color, 
           int? internalMemory, string operatingSystem)
    {
        _brand = brand;
        _model = model;
        _color = color;
        _internalMemory = internalMemory;
        _operatingSystem = operatingSystem;
    }

    public string Brand{get{ return _brand;}}
    public string Model{get{ return _model;}}
    public MobileColor Color{get{ return _color;}}
    public int? InternalMemory{get{ return _internalMemory;}}
    public string OperatingSystem{get{ return _operatingSystem;}}


    public bool IsEqual(MobileSpec mobileSpec)
    {

        if (!string.IsNullOrEmpty(mobileSpec.Brand) && mobileSpec.Brand.ToLower() != Brand.ToLower())
            return false;

        if (!string.IsNullOrEmpty(mobileSpec.Model) && mobileSpec.Model.ToLower() != Model.ToLower())
            return false;

        if (mobileSpec.Color != MobileColor.None && mobileSpec.Color != Color)
            return false;

        if (!string.IsNullOrEmpty(mobileSpec.OperatingSystem) && 
                     mobileSpec.OperatingSystem.ToLower() != OperatingSystem.ToLower())
            return false;

        if (mobileSpec.InternalMemory.HasValue && mobileSpec.InternalMemory != InternalMemory)
            return false;

        return true;

    }
}

Congratulations! You have written good software

These are the some basic rules and by following them you can write Good Software every time. Just make it your habit and enjoy your work.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Shakeel Iqbal
Software Developer (Senior) TEO
Pakistan Pakistan
Passion and positive dedication is essential part of success. I believe on hardworking and sharing knowledge with others. I always try to be a better than I am and think positive for positive result.
 
My Blogs
Follow on   Twitter   Google+

Comments and Discussions

 
Generaluseful site PinmemberMember 1065838710-Mar-14 5:32 
GeneralGood article, thank you PinmemberJacory Gao21-Dec-13 21:43 
Generalgood article for newbies Pinmembersyntax10117-Oct-13 20:28 
GeneralMy vote of 3 PinmemberMember 1027497512-Oct-13 2:30 
GeneralMy vote of 2 PinmemberWerner Putschögl7-Oct-13 1:53 
GeneralMy vote of 2 PinprofessionalPaulo Zemek3-Oct-13 17:38 
GeneralMy Vote of 2 Explained. PinprofessionalPaulo Zemek3-Oct-13 17:38 
GeneralRe: My Vote of 2 Explained. PinmvpFlorian Rappl7-Oct-13 11:50 
GeneralMy vote of 3 Pinmemberlearner'sbug2-Oct-13 9:52 
GeneralMy vote of 5 PinmemberURVISH_SUTHAR126-Sep-13 22:03 
Generalvery good Pinmember314061826-Sep-13 16:53 
GeneralMy vote of 5 PinmemberJayanta Chatterjee26-Sep-13 3:39 
GeneralRe: My vote of 5 PinmemberShakeel Iqbal26-Sep-13 6:31 
GeneralMy vote of 5 PinmemberMember 1027707326-Sep-13 1:21 
GeneralMy vote of 5 Pinmembershahid26625-Sep-13 7:12 
GeneralMy vote of 5 PinmemberJahanzaib Rahman25-Sep-13 6:24 
GeneralMy vote of 5 Pinmemberi_islamian25-Sep-13 6:21 
GeneralMy vote of 5 PinprofessionalMember 1028457625-Sep-13 2:23 
GeneralRe: My vote of 5 PinmemberShakeel Iqbal25-Sep-13 2:41 
GeneralMy vote of 5 PinmemberMember 982586824-Sep-13 21:20 
GeneralMy vote of 5 Pinmemberwaqarii24-Sep-13 9:04 
GeneralMy vote of 5 PinmemberMember 1029508024-Sep-13 8:46 
QuestionA suggestion. PinmemberGeorge Swan24-Sep-13 8:37 
AnswerRe: A suggestion. PinmemberShakeel Iqbal24-Sep-13 8:53 
QuestionThis isn't teaching you how to write good software. PinprotectorPete O'Hanlon24-Sep-13 4:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 26 Sep 2013
Article Copyright 2013 by Shakeel Iqbal
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid