Software Engineering Good Practices

LiveRunGrow
5 min readAug 4, 2020

--

Associations

  • Connections between objects
  • Navigability -> Concept of which class in the association knows about the other class
  • Multiplicity -> Dictates how many objects take part in each association.
  • Dependencies -> Objects that are not directly linked in the object network. They are weaker forms of associations. For eg, an object does not keep another object it receives as a parameter.
  • Composition -> Represents a strong whole-part relationship. When the whole is destroyed, parts are destroyed too. HAS-A relationship.
  • Aggregation -> Weaker than composition. It represents a container-contained relationship. The containee object can exist even after the container object is deleted.

Inheritance

  • IS-A relationship
  • Overriding -> When a sub-class changes the behaviour inherited from the parent class by over-riding the method. Overriden methods have the same type signature, name, return type.
  • Overloading -> When there are multiple methods with the same name but different type signature.
  • Note that return types and parameter names are not considered part of the type signature.
  • Interface -> A behaviour specification. If a class implements the interface, it means the class can support the methods specified in the interface.
  • Abstract class -> May or may not include abstract methods. Cannot be instantiated but can be subclassed.
  • An abstract method is simply the method interface without the implementation.
  • Overriden methods are resolved during dynamic binding while overloaded methods are resolved during static binding.

Polymorphism

  • The ability of different objects to respond, each in its own way, to identical messages.
  • Eg, we can have an ArrayList of Staff where staff can have further subclasses called admin-staff, Professors etc. But we treat them as one object type, Staff.
  • 3 concepts combine to achieve polymorphism.
  • 1) Substitutability: Can write code that expects object of a parent class and yet use that code for objects of child classes.
  • 2) Overriding: Allows the operation in the superclass to be overriden in each of the subclasses.
  • 3) Dynamic binding: Calls to overriden methods are bound to the implementation of the actual object’s class dynamically during the runtime.

An interface is a behaviour specification with no implementation

A class is a behaviour specification + implementation

An abstract class is a behaviour specification+ a possibly incomplete implementation

Design Fundamentals

  1. Abstraction
  2. Coupling -> A measure of the degree of dependence between components, classes, methods, etc. Low coupling means that a component is less dependent on other components.
  3. Cohesion -> A measure of how strongly-related and focused the various responsibilities of a component are. A high cohesive component keeps related functionalities together while keeping out all other unrelated things. Higher cohesion is better.

Software Design Patterns

Design pattern: An elegant reusable solution to a commonly recurring problem within a given context in software design.

  • Singleton Pattern: A certain class should have no more than just one instance. These single instances are commonly known as singletons. The problem is that a normal class can be instantiated multiple times by invoking the constructor. The solution is to make the constructor of the singleton class private and provide a public class-level method to access the single instance.
  • Cons: The singleton object act like a global variable that increases coupling across the code base. In testing, it is difficult to replace Singleton objects with stubs as static methods cannot be overriden.
  • Abstraction Occurrence Pattern:
  • Facade Pattern: Components need to access functionalities deep inside other components. The problem is that access to the component should be allowed without exposing its internal details. Hence, the solution is to create a Facade class that sits between the component internals and users of the component such that all access to the component happens through the Facade class.
  • Command Pattern: A system is required to execute a number of commands, each doing a different task. For eg, a system might have to support Sort, List, Reset commands. The problem is that it is preferable that some parts of the code executes these commands without having to know each command type. The solution is to have a general Command object that can be passed around without knowing the type of command.
  • Model View Controller Pattern: Most applications support storage/retrieval of information, displaying of information to the user, and changing stored information based on external inputs. The problem is that we want to reduce coupling resulting from the interlinked nature of the features described above. The solution is to decouple data, presentation and control logic of an application by separating them into 3 components: Model, View, Controller.
  • View: Displays data, interact with user, pull data from model
  • Model: Stores and maintains data. Updates view when necessary.
  • Controller: Detects UI events such as mouse clicks, button pushes and take follow up action. Updates model/view when needed.
  • Observer Pattern: The problem is that the ‘observed’ object does not want to be coupled to objects that are ‘observing’ it. To solve it, we force the communication through an interface known to both parties. The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependencies, and notifies them when its’ state changed, usually by calling their methods.

Code Quality

  • SLAP Hard -> Single level of abstraction per method
  • Make the Happy path prominent -> Unusual cases should be indented.
  • Avoid empty catch statement.

Quality Assurance

  • Validation: Are we building the right system, are the requirements correct? Does it solve the problems?
  • Verification: Are we building the system right? Are the requirements implemented correctly?
  • Unit Testing: Testing individual unites (methods, classes, subsystems…) to ensure each piece works correctly.
  • Stubs: Isolate code from possible bugs in dependencies
  • Integration Testing: Testing whether different parts of the software works together as expected.
  • System Testing: Based on the specified external behaviour of the system.
  • Alpha Testing: Performed by the users, under controlled conditions set by the software development team.
  • Beta Testing: Performed by a selected subset of target users of the system in their natural work setting.

Principles

  • Single-Responsibility Principle: A class should have one, and only one, reason to change. It only changes when there is a change to that responsibilities.
  • Open-Closed Principle: A module should be open for extension but closed for modifications. It should be written in a way so that they can be extended.
  • Liskov Substitution Principle: Derived classes must be substitutable for their base classes.
  • Separation of Concerns Principle: To achieve better modularity, separate the code into distinct sections, such that each section addresses a separate concern.
  • Law of Demeter: An object should have limited knowledge of another object and interact with objects that are closely related to it.

--

--

LiveRunGrow
LiveRunGrow

Written by LiveRunGrow

𓆉︎ 𝙳𝚛𝚎𝚊𝚖𝚎𝚛 🪴𝙲𝚛𝚎𝚊𝚝𝚘𝚛 👩‍💻𝚂𝚘𝚏𝚝𝚠𝚊𝚛𝚎 𝚎𝚗𝚐𝚒𝚗𝚎𝚎𝚛 ☻ I write & reflect about software engineering, my life and books. Ŧ๏ɭɭ๏ฬ ๓є!

No responses yet