Object-Oriented Programming

Basic UML Notation

The class is denoted with 3 parts: The class name, its attributes, and its methods.

Instances of a class are denoted with 3 parts: its name (and class), and its attribute values.

Class-level attributes and variables are denoted by underlines. In the class diagram below, totalStudents and getTotalStudents are class-level._

UML Notation for enumerations:



Inheritance allows you to define a new class based on an existing class. This helps group common parts among classes. This is denoted by an arrow.


An interface is a behaviour specification. If a class implements the interface, it is able to support the behaviours specified by the interface. A class implementing an interface results in an is-a relationship. In the example below, AcademicStaff is a SalariedStaff.

An abstract method is the method interface without the implementation. It is denoted with the {abstract} annotation in the UML diagram.


Polymorphism is the ability of different objects to respond, each it its own way, to identical messages. The mechanisms that enable polymorphism are:

write code that expects parent class, yet use that code with objects of child classes.
Operations in the super class need to be overridden in each of the subclasses.
Dynamic binding
Calls to overridden methods are bound to the implementation of the actual object’s class dynamically during runtime.

Modelling Behaviour

Activity Diagrams

Rectangles with rounded edges (Steps)
Control flows
Lines with arrowheads (Flow of control from one action to another)
Alternate paths
Diamond shapes
  • Branch or merge nodes
  • Each control flow leaving branch node has guard condition
  • Only 1 alernative path can be taken at any time.
Parallel paths
  • Forks and join
  • Indicate start and end of concurrent flows of control
Part of Activity
  • Indicate that part of activity is given as separate diagram
  • In actions
Actor partitions
  • Partition activity diagram to show who is doing which action (Who label at the top, as columns)

Sequence Diagrams

Method calls
Solid arrows
Method returns
Dotted arrows (optional)
labeled boxes

Activation bar (optional) - Method is running and in charge of execution - Constructor is active - Dotted lines after activation bar shows a lifeline, i.e. it is still alive

Use a X at end of lifeline of an object
Self Invocation
Draw a second bar within the activation bar for inner method and an arrow to show self invocation
Alternative paths
Alt frames (boxes) with dotted horizontal lines to separate alternative paths
Optional paths
Opt frames
Reference frames
  • ref frame to omit details/ Show frame in another sequence diagram
  • sd frame to show details
Parallel paths
For multi-threading, as multiple things are being done at the same time


Software Requirements

Requirements come from stakeholders: parties that are directly affected by the software project.

functional requirements
specify what the system should do
  • data requirements: availability etc.
non-functional requirements
specify the constraints under which system is developed
  • business and domain rules: the size of the group cannot be more than 5
  • constraints: should be backwards compatible
  • technical requirements: should work on 3264-bit environments

Good requirements are: unambiguous, testable, clear, correct, understandable, feasible, independent, atomic, necessary, implementation-free

User stories follow the format: As a _, I can _ so that _. They occur on different levels, high-level stories are called epics.


Software design has 2 main aspects:

  1. product/external design: designing the external behaviour of the product to meet the user requirements.
  2. implementation/internal design: designing how the product will be implemented to meet the required external behaviour.

  3. technique for dealing with complexity, establishes a level of complexity we are interested in, and suppressing more complex details below that level.


Coupling is the measure of the degree of dependence between components. Highly coupled components are:

Coupling comes in various forms:

Content Coupling
one module modifies or relies on the internal workings of another module.
Common/Global Coupling
two modules share the same global data
Control Coupling
one module controls the flow of the other
Data Coupling
one module sharing data with another module (e.g. passing params)
External Coupling
two modules share an externally imposed convention
Subclass Coupling
a class inherits from another class
Temporal Coupling
two actions are bundled together because they happen to occur at the same time


Cohesion is a measure of how strongly-related and focused the various responsibilities of a component are. Low cohesion can:

Cohesion can be present in many forms:

Software Architecture

Software architecture shows the overall organization of the system and can be viewed as a very high-level design.

Architectural Styles

  1. n-tier

    • n layer
    • Higher layer communicates to lower tier
    • Must be independent
  2. Client-server

    • At least one client component and one server component
    • Commonly used in distributed apps
  3. Event-driven Style

    • Detect events from emitters and communicating to event consumers
  4. Transaction processing style

    • Divides workload down to a number of transactions which are given to a dispatcher which controls the execution for each transaction
  5. Service-oriented architecture (SOA)

    • Combining functionalities packaged by programmatically accessible services
    • e.g. Creating an SOA app that uses Amazon web services
  6. Pipes and Filters pattern

    • Break down processing tasks by modules (streams) into separate components(filters), each into 1 task
    • Combine them into a pipeline by standardising format of data each component sends and receives
    • Bottleneck - Slowest filter
    • Components can be run independently
    • Used when processing steps by an application have different scalability requirements
  7. Broker pattern

    • Broker component coordinates communication, such as forwarding requests, as well as for transmitting results and exceptions
    • Used to structure distributed software systems with decoupled components interacting by remote service invocations
  8. Peer-to-peer

    • Partitions workload between peers (both ‘client’ and ‘server’ to other nodes)
  9. Message-driven processing

    • Client sends service requests in specially-formatted messages to request brokers(programs)
    • Request brokers maintain queues of requests (and maybe replies) to screen their details

Software Design Patterns

Software Design Patterns are elegant reusable solutions to commonly recurring problems within a given context in software design.

Design patterns are specified with: context, problem, solution, anti-patterns, consequences and other useful information.


Abstraction Occurrence

Facade Pattern

Command Pattern

MVC Pattern

Observer Pattern


process of discovering defects in the program.
  • inserting temporary print statements incur extra effort, manually tracing through code is difficult and time consuming. We should use a debugger tool, which allows pausing and stepping through execution of the code.

Code Quality

There are various dimensions of code quality, including run-time efficiency, security, and robustness. The most important perhaps is readability.

Some basic guidelines:

  1. Avoid long methods
  2. Avoid deep nesting
  3. Avoid complicated expressions
  4. Avoid Magic numbers
  5. Make the code obvious, e.g. by using explicity type conversion
  6. Structure code logically
  7. Do not trip up the reader, with things like unused parameters in the method signature
  8. Practice KISSing
  9. Avoid premature optimizations
  10. Make the happy path prominent
  11. SLAP (Single level of abstraction per method) hard
  12. Make the happy path prominent

It is also good to follow a coding standard.

Comments should explain the what and why, and not the how. Write comments minimally but sufficiently, not repeating the obvious and writing with the reader in mind.


Refactoring improves a program’s internal structure in small steps without modifying its external behaviour. It is not rewriting, and not bug-fixing.

Common refactors include:

Error Handling

Exceptions are events that occur during the execution of a program, that disrupt the normal flow of the program’s instructions.

Exception objects encapsulate the unusual situation so that another piece of code can catch it and deal with it. Exception objects propagate up the method call hierarchy until it is dealt with.


Assertions are used to define assumptions about the program state so that the runtime can verify them. If the runtime detects an assertion failure, it typically takes some drastic action, such as terminating the program. Assertions can be disabled without modifying the code.


Logging is The deliberate recording of certain information during program execution for future reference, and is useful for troubleshooting problems. Most languages come with a logging mechanism, and the logger has different levels: SEVERE, INFO, WARNING etc.

Build automation

  1. Gradle

    • Automates tasks such as:

      • Running tests
      • Manage library dependencies
      • Analyse code for style compliance
    • Gradle configuration is defined in build script build.gradle

    • Gradle commands are run in gradlew (wrapper) which runs the following commands by default:

      • clean
      • headless
      • allTests
      • coverage
    • Dependencies are updated automatically by other relevant Gradle tasks

Continuous Integration (CI)

  1. Integration, building and testing happens automatically after code change
  2. Travis CI
  3. Continuous Deployment (CD) - Changes are integreated, and deployed to end-users at the same time (e.g. Travis)

Defensive Programming


DbC is an *approach for designing software that requires defining formal, precise and verifiable interface specifications for software components*.

Integration Approaches

  1. Late and one-time
    • Wait till all components are completed and integrate all finished components near end of project
    • Not recommended due to possible component incompatabilities, which can lead to delivery delays
  2. Early and frequent
    • Integrate early and evolve each part in parallel, in small steps, re-integrating frequently
  3. Big-Bang vs Incremental Integration
    • Big-bang can lead to many problems at the same time
  4. Top-Down vs Bottom-Up
    • Top-Down require stubs
    • Bottom-up require drivers
    • Sandwich for both to ‘meet’ in the middle


By reusing tried and tested components, the robustness of a new software system can be enhanced while reducing the manpower and time requirement. There are costs associated with reuse.


An Application Programming Interface (API) specifies the interface through which other programs can interact with a software component.

Libraries and Frameworks

A library is a collection of modular code that is general and can be used by other programs. A software framework is a reusable implementation of a software providing generic functionality that can be selectively customized to produce a specific application. Libraries are meant to be used ‘as is’ while frameworks are meant to be customized/extended. Your code calls the library code while the framework code calls your code.


A platform provides a runtime environment for applications. A platform is often bundled with libraries, tools and frameworks.

Quality Assurance

QA ensures that the software being built has the required levels of quality. This is achieved through:

code reviews
the systematic examination of code with the intention of finding where the code can be improved
static analysis
analysis of the code without actually executing the code (e.g. Linters)
formal verification
mathematical techniques, used to prove the correctness of a program. it can only be used to prove the absence of errors, but only proves compliance with the specification, and not the actual utility of the software.


When testing, we execute a set of test cases, containing the input and the expected behaviour. Test cases can be determined based on the specification.

Unit Testing

Integration Testing

System Testing


Exploratory vs Scripted Testing

Acceptance Testing

System Testing Acceptance Testing
done against the system specification Done against the requirements specification
done by testers on the project team done by a team that represents the customer
done on the development environment done on the deployment site, or a close simulation
both negative and positive test cases focus on positive test cases


Coverage is the metric used to measure the extent to which testing exercises the code.

function/method coverage
based on the functions executed
statement coverage
based on the number of lines of code executed
decision/branch coverage
based on the decision points exercised
condition coverage
based on the boolean sub-expressions
path coverage
in terms of possible paths through a given part of the code executed
entry/exit coverage
in terms of possible calls to and exits from the operations in the SUT

Test Case Design

designed exclusively based on the SUT’s specified external behaviour
test cases are designed based on what is known about the SUT’s implementation
uses some important information about the implementation.

Equivalence partitions are groups of test inputs that are likely to be processed by the SUTs in the same way. This can be determined by identifying:

  1. target object of method call
  2. input parameters of method call
  3. other data objects accessed by the method, such as global variables.

Boundary Value analysis is a *test case design heuristic that is based on the observation that bugs often result from incorrect handling of boundaries of equivalence partitions*.

Other heuristics include:

Software Engineering Principles

Law of Demeter

  1. An object should have limited knowledge of another object
  2. An object should have limited interaction with closely related classes, if foo is coupled to bar, which is coupled to goo, foo should not be coupled to goo
  3. Reduces coupling


Single Responsibility Principle
every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class.
Open-Closed Principle
software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behaviour to be extended without modifying its source code.
Liskov Substitution Principle
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.- Interface Segregation Principle :: no client should be forced to depend on methods it does not use.
Dependency Inversion Principle
high level modules should not depend on low level modules; both should depend on abstractions. Abstractions should not depend on details.
a principle of extreme programming (XP) that states a programmer should not add functionality until deemed necessary.
Don’t repeat yourself, i.e. No duplicate implementations
Brook’s Law
Adding people to a late project makes it later

Software Development Life Cycles

SDLC consists of different stages such as:

Sequential models

  1. Software development as linear process
  2. Useful for problems that are well-understood and stable

    • Rarely applicable in real-world projects
  3. Each stage provides artifacts for use in next stage

Iterative models

  1. Several iterations
  2. Each iteration is a new version

    • Each iteration is a complete product
  3. Either breadth-first (all major components in parallel) or depth-first (Flesh out some components at a time)

  4. Most projects use both, i.e. iterative and incremental process

Agile models


Extreme Programming (XP)

  1. Stresses customer satisfaction
  2. Empowers developers to respond to changing customer requirements
  3. Emphasises teamwork
  4. Completes software project via:
    • Communication
    • Simplicity
    • Feedback
    • Respect
    • Courage

Unified process

CMMI (Capability Maturity Model Integration)