Personal notes on software development.
For Java technologies check my dedicated site

Pages

Overview

To master software design you have to start on the basis and then dig deeper into bigger things that depend on the previous ones. An ordered approach, step by step, would be:

1. Understand the Object-Oriented Paradigm/OO Basis/OO Principles/OO characteristics/OO Concepts

A computer language is "object-oriented" if they support the 4 specific object properties:
  • abstraction: in OO it means abstraction of the code details and think in terms of classes (classes define object characteristics like: properties, state and actions), i.e. think in a representation/model of the real world. Example: we can create two classes  Cat and Dog that are subclasses of the class Animal: this classes represent a model of the real world and helps us think in a more natural way: where objects have their own properties (like animal "weight"), state(like "currently sleeping"), actions (like "run" or "talk") and can perform and interact with other objects to accomplish different tasks; 
  • encapsulation: is when you hide parts of your data from the rest of your application, and limit the ability for other parts of your code to access that data. An example of encapsulation is using accessors/mutators (get and set methods) instead of accessing class variables directly, this way you can add and ensure any logic gets performed each time the variable is set/get (private variable and public get/set methods);
  • inheritance:  its when a class inherits behavior from another class and can then change that behaviour if needed; Inheritance lets you build classes based on other classes and avoid duplicating and repeating code;
  • polymorphism: when one class inherits from another (or when different classes implement the same interface or abstract class), then polymorphism allows classes to be used interchangeably. E.g. The classes "Dog" and "Cat", bouth can inherit from a "Animal" class. If they do, then we can put "Dog" and "Cat" objects in a List<Animal> because they are all "Animals" and use any method defined by "Animal" without caring if they are actually a "Dog" or a "Cat" instance.

2. Design Principles

Knowing the OO basics does not make you a good OO designer! Good OO designs are: reusable, extensible and maintainable.
Software design principles represent a set of guidelines that helps us to avoid having a bad design. The design principles are associated to Robert Martin who gathered them in "Agile Software Development: Principles, Patterns, and Practices". According to Robert Martin there are 3 important characteristics of a bad design that should be avoided:
   - Rigidity - It is hard to change because every change affects too many other parts of the system;
   - Fragility - When you make a change, unexpected parts of the system break;
   - Immobility - It is hard to reuse in another application because it cannot be disentangled from the current application;

Some popular/main design principles include:
  • Open Close Principle: software entities like classes, modules and functions should be open for extension but closed for modifications;
  • Dependency Inversion Principle: high-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions;
  • Interface Segregation Principle: clients should not be forced to depend upon interfaces that they don't use;
  • Single Responsibility Principle: a class should have only one reason to change;
  • Liskov's Substitution Principle: derived types must be completely substitutable for their base types;
  • Don't Repeat Yourself (DRY): avoid duplicate code by abstracting ou things that are common and placing those things in a single location; DRY is about having each piece of information and behaviour in your system in a single, sensible place;
  • Single Responsibility Principle (aka Cohesion): every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class. This is the same as a class having only one reason to change; Cohesion is another name for the SRP: If you're writing highly cohesive software, then that means that you're correctly applying the SRP;
  • KISS ("Keep it simple, Stupid!" or "keep it short and simple" or "keep it simple AND stupid" or "keep it simple and straightforward"): its a general principle (applied in many different areas like music, art, engineering and, of course, software design). It states that simplicity should be a key goal in design, and that unnecessary complexity should be avoided. Although all this design principles aim to achieve good designs, providing greater flexibility, they also increase complexity: you only need to respect them when your project really needs the flexibility they provide, otherwise keep it simple!
    Albert Einstein: "tudo deve ser feito da forma mais simples possível, mas não mais simples que isso";
    Antoine de Saint-Exupéry "A perfeição é alcançada não quando não há mais nada para adicionar, mas quando não há mais nada que se possa retirar";

3. Design Patterns


  • Patterns show you how to build systems with good OO designs qualities;
  • Patterns are proven object oriented experience;
  • Patterns don't give you code, they give you general solutions to design problems. You apply them to your specific application;
  • Patterns aren't invented they are discovered;
  • Most patterns and principles address issues of change in software: they can be applied to prepare an application for future modifications (due to changing requirements), but they can also be used to extend applications functionality without breaking the existing one (without causing errors on old functionality).
  • Most patterns allow some part of a system to vary independently of all other parts: loosely-coupled designs;
  • Patterns provide a shared language (by naming the design solutions) that can maximize the value of your communication with other developers;




Online references:

   1. Object Oriented Paradigm
   2. Design Principles
   3. Design Patterns

Book references:

Only start worrying about design an architecture after you have the basic OO knowledge like:
  • inheritance: its when a class inherits behaviour from another class and can then change that behaviour if needed; Inheritance lets you build classes based on other classes and avoid duplicating and repeating code; Some related terms and code examples (in Java) are:
    public class Jet extends Airplane 
    this means Jet inherits all behaviour from Airplane to use for its own; So, Jet is called a subclass of Airplane and Airplane is a superclass for Jet.
    Jet can call the special keyword super() that calls the constructor of Airplane (Jet's superclass). Jet can change the behaviour of its superclass, as well as call the superclass's methods: this is called overriding. Overriding example:
    public void setSpeed(int speed){
    super.setSpeed(speed * MULTIPLIER);
    }
  • polymorphism: is closely related to inheritance. When one class inherits from another, then polymorphism allows a subclass to stand in instead of the superclass. Example:
    if we have:
    public class Jet extends Airplane; 
    then we can do:
    Airplane plane1 = new Airplane();
    Airplane plane2 = new Jet(); 
    This is very useful because you can write code that can work on the superclass, like Airplane, but it will work with a any subclass type, like Jet or Rocket, so your code will be more flexible and you can treat this different types like one type only (for example you can create an array of Airplane and fill it with Jet and Rocket objects since their are all Airplane).
  • encapsulation: is when you hide parts of your data from the rest of your application, and limit the ability for other parts of your code to access that data. An example of encapsulation is using get() and set() methods instead of accessing class variables directly, this way you can add and ensure any logic gets performed each time the variable is set/get (private variable and public get/set methods); So encapsulation protects data from being set in an improper way - with encapsulated data any calculations or checks that the class does on the data are preserved, since the data can't be accessed directly. A more formal definition: encapsulation is the process of enclosing programming elements inside larger, more abstract entities. Also known as information hiding or separation of concerns. Encapsulation separates your data from your app's behaviour. Then you can control how each part is used by the rest of your application. You can also encapsulate groups of data, or even behaviour to control how they are accessed. Encapsulation is when you separate or hide one part of your code from the rest of your code.
 Basic experience with a OO programming language like Java or C# (knowledge on things like  abstract classes, interfaces, etc.) is also mandatory.

So assuming you already have this background the next step is learning design principles like: High Cohesion, Low Coupling Open Closed Principle, DRY, Liskov Substitution Principle etc. For these fundamentals some people recommend reading the following books in this order:
  1. Head First Object-Oriented Analysis and Design (Head First) (Language: Java and UML). This book is useful for programmers with a bit of Java (or C#) knowledge who want to get a good overview of OOA&D. It teaches important OO vernacular and a simple holistic approach to iterative development. For a more thorough explanation of these topics some people recommend "The Object Primer" by Scott Ambler as a good introduction to OOA&D too;
  2. Applying UML and Patterns (Language: Java and UML);
  3. Agile Principles, Patterns, and Practices in C# (Robert C. Martin Series) (Language: C#);
After mastering this fundamentals you are ready for the basic GoF (gang of four) design patterns (around 23 distinct patterns):
  1. Head First Design Patterns (Head First);
  2. Design Patterns: Elements of Reusable Object-Oriented Software is the bible of design patterns. The first book on this matter written by the famous Gang of Four (GoF). The GoF patterns are generally considered the foundation for all other patterns. But remember design patterns are not invented they are discovered;
The next step:
  1. Patterns of Enterprise Application Architecture (Martin Fowler, 2002)  is written in direct response to the stiff challenges that face enterprise application developers. The author, noted object-oriented designer Martin Fowler, noticed that despite changes in technology--from Smalltalk to CORBA to Java to .NET--the same basic design ideas can be adapted and applied to solve common problems. The entire book is also richly illustrated with UML diagrams to further explain the concepts.
    The topics covered include:
    - Dividing an enterprise application into layers
    - The major approaches to organizing business logic
    - An in-depth treatment of mapping between objects and relational databases
    - Using Model-View-Controller to organize a Web presentation
    - Handling concurrency for data that spans multiple transactions
    - Designing distributed object interfaces
  2. The POSA (Pattern-Oriented Software Architecture) book series;
  3. Search for specific domain design patterns relevant for your area, some key words could be: Gang of Four Patterns; Head First Patterns; Enterprise Patterns; SOA Patterns; WPF Best Practices; WCF Best Practices; LINQ Best Practices; Model View Controller; Model View Presenter; Model View ViewModel; etc.


More books on this area can be found on multiple amazon book categories like:
  • Books > Computers & Internet > Programming > Software Design, Testing & Engineering > Object-Oriented Design
  • Books > Computers & Internet > Programming > Software Design, Testing & Engineering > UML
  • Books > Computers & Internet > Programming > Software Design, Testing & Engineering > Software Development
  • Books > Computers & Internet > Computer Science > Software Engineering > Design Tools & Techniques
  • Books > Computers & Internet > Computer Science > Software Engineering > Methodology
  • Books > Computers & Internet > Computer Science > Systems Analysis & Design
  • Books > New & Used Textbooks > Computer Science > Software Design & Engineering
  • Books > New & Used Textbooks > Computer Science > Object-Oriented Software Design

Object-oriented analysis and design (OOAD) notes:

OOAD is all about writing "great code":
  • well designed;
  • well coded;
  • easy to maintain, reuse and extend;
"Great code" from  3 different user perspectives:
  • The client: great software always does what the customer wants it to. So even if customers think of new ways to use the software, it doesn't break or give them unexpected results;
  • OO programmer: great software is code that is object-oriented. So there's not a bunch of duplicate code, and each object pretty much controls its own behaviour. It's also easy to extend because your design is really solid and flexible;
  • Design-guru programmer: great software is when you use  tried-and-true design patterns and principles. You've kept your objects loosely coupled, and your code open for extension but closed for modification. That also helps make the code more reusable, so you don't have to rework everything to use parts of your application over and over again;

3 ordered steps you can take to make sure your software does what it's supposed to,  is well-designed and easy to reuse:
  • 1º Make sure your software does what the customer wants it to do (focus on functionality without making big design considerations. But do use good OO principles and techniques if they came naturally); This is were getting good requirements and doing some analysis comes in;
  • 2º Apply basic OO principles to add flexibility. Once your software works, you can look for any duplicate code that might have slipped in and make sure you're using good OO programming techniques (principles like delegation, encapsulation, inheritance and polymorphism makes your code more flexible);
  • 3º Strive for a maintainable reusable design: got a good object-oriented app that does what it should? It's time to apply patterns and principles to make sure your software is ready to use for years to come (easy to maintain, reuse and extend); Once you've applied some basic OO principles in 2º step, you're ready to apply some patterns and really focus on reuse (answer to client change request or reusing just a few parts of the app in other contexts); For example, adding properties to some Class shouldn't affect the code in the rest of the application: cascading changes.

You should make sure that the application works like it should before you dive into applying design patterns or trying to do any real restructuring of how the application is put together. You're going to make lots of changes to your software when you're getting it to work right. Trying to do too much design before you've at least got the basic functionality down can end up being a waste, because a lot of design will change as you're adding new pieces of functionality to your classes and methods.
Building an application that works well but is poorly designed satisfies the customer but will leave you with pain, suffering, and lots of late nights fixing problems.

Remember: Analysis and design are all about making choices and sometimes you're going to make a different choice than another programmer. There's nothing wrong with that, as long as you have good, well thought out reason for the decision you made.OOA&D and software development aren't about making a particular decision, since many times there isn't an exactly "right" or exactly "wrong" choice. They're about writing well-designed software, and that can happen in a lot of different ways. Design decisions are always a tradeoff.
Good software is built iteratively. Analyse, design and then iterate again, working on smaller and smaller parts of your app. Each time you iterate, re-evaluate your design decisions and don't be afraid to CHANGE something if it makes sense for your design.
Lots of design decisions look great at once stage of your development, but then turn out to be a problem as you get deeper into a particular part of your app. As long as your design is working and you're able o use good OO principles and apply design patterns, you're in good shape. If you start running into trouble with a decision, though, don't ever be afraid to change designs and rework things.
You always have to make a choice, even if you're not 100% sure if's the right one. It's always better to take your best guess, and see how things work out, rather than spend endless hours debating one choice or another. That's called analysis paralysis, and it's a sure way to not get anything done. It's much better to start down one path, even if you're not totally sure it's the right one and get some work done, than to not make a choice at all



Terms and principles

  • Flexibility: use me so that your software can change and grow without constant rework. I keep your application from being fragile; By introducing principles like encapsulation and good class design into your code, it's easier to make these changes, and your application becomes a lot more flexible; Personal note: Too much flexibility can male the code ambiguous. ()
  • Functionality: without me, you'll never actually make the customer happy. No matter how well-designed your application is. I'm the thing that puts a smile on the customer's face;
  • Encapsulation: use me to keep the parts of your code that stay the same separate from the parts that change; then it's really easy to make changes to your code without breaking everything; If you've got tons of duplicate code or confusing inheritance structures in your app, making changes is going to be a pain; You can use OO principles like encapsulation and delegation to build applications that are flexible; Encapsulation is breaking your application up into logical parts;
  • Design Pattern: i'm all about reuse and making sure you're not trying to solve a problem that someone else has figured out; with a functional and flexible design, you can employ design patterns to improve your design further, and make your app easier to reuse; Design patterns are great for various reasons:
    - gives you a starting for solving common problems;
    - gives developers a vocabulary to talk about certain ways of solving problems in a very compact manner;
    - when working with developers who know design patterns and you use design patterns in your solutions they will understand the solutions a lot faster;
  • Design principle: is a basic technique that can be applied to designing or writing code to make that code more maintainable, flexible or extensible; Some examples are:
    - encapsulate what varies;
    - code to an interface rather than to an implementation;
    - each class in your application should have only one reason to change;
    - classes are about behaviour and functionality;
    - Open-Closed Principle (OCP): Classes should be open for extension and closed for modification; closed because nobody can change the behaviour of your code because you've locked it in a class. But open because you allow people to subclass and extend your class and override their methods (OCP achieved by inheritance); Another example of OCP could be: if you had several private methods in a class, those are closed for modification - no other code can mess with them. But then you could add several public methods in different ways (you're extending the behaviour of the private methods, without changing them);
    - Don't Repeat Yourself (DRY): avoid duplicate code by abstracting ou things that are common and placing those things in a single location; DRY is about having each piece of information and behaviour in your system in a single, sensible place;
    - Single Responsibility Principle (SRP): Every object in your system should have a single responsibility, and all the object's services should be focused on carrying out that single responsibility; this is the same as a class having only one reason to change; Cohesion is another name for the SRP: If you're writing highly cohesive software, then that means that you're correctly applying the SRP.
    - Liskov Substitution Principle (LSP): subtypes must be substitutable for their base types; The LSP is all about well-designed inheritance. When you inherit from a base class, you must be able to substitute your subclass for that base class without things going terribly wrong, otherwise you've used inheritance incorrectly. When you find code that violates the LSP, consider using delegation, composition, or aggregation to use behavior from other classes without resorting to inheritance. If you favour delegation, composition, and aggregation over inheritance, your software will usually be more flexible, and easier to maintain, extend and reuse;

    NOTE: see also SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion)
  • Delegation: delegation is when an object needs to perform a certain task, and instead of doing that task directly, it asks another object to handle the task (or sometimes just a part of the task); Delegation makes your code more reusable. I also lets each object worry about its own functionality, rather than spreading the code that handles a single object's behaviour all throughout your application. One of the most common examples of delegation in Java is the equals() method. Instead of a method trying to figure out if two objects are equal, it calls equals() on one of the objects and passes in the second object. Then it just gets back a true or false response from the equals() method. This means objects are more independent of each other, or more loosely coupled; If you need to use functionality in another class, but you don't want to change that functionality, consider using delegation instead of inheritance [1 - pag. 441];
  • Loosely coupled objects can be taken from one app and easily reused in another because they're not tightly tied to other objects code. Loosely coupled is when the objects in your application each have a specific job to do, and they do only that job. So the functionality of your app is spread out over lots of well-defined objects, which each do a single task really well; Loosely coupled applications are usually more flexible, and easy to change. Since each object is pretty independent of the rest of your objects. so adding new features or functionality becomes a lot easier.
  • UML (Unified Modeling Language):  is a language used to communicate just the details about your code and application's structure that other developers and customers need, without getting details that aren't necessary (it's pretty hard to look at 200 lines of code and focus on the big picture). For example, a class diagram makes it really easy to see the big picture: you can easily tell what a class does at a glance.Class diagrams are just a way to communicate the basic details of a class's variables and methods. It makes it wasy to talk about code without forcing us to see the code. By using a standard like UML, we can all seak the same language and be sure we're talking about the same thing in our diagrams;

No comments:

Post a Comment