Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
7 views

Unit 20 - Applied Programming and Design Principles_2022

The document outlines the internal verification process for assessment decisions related to the BTEC Higher National Diploma in Computing, specifically focusing on Unit 20: Applied Programming and Design Principles. It includes details about the assignment titled 'Sales Analysis System for Sampath Food City (PVT) Ltd', assessment criteria, and guidelines for submission, along with a grading rubric for evaluating student performance. Additionally, it emphasizes the importance of adhering to academic integrity and the consequences of plagiarism.

Uploaded by

89thisara
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Unit 20 - Applied Programming and Design Principles_2022

The document outlines the internal verification process for assessment decisions related to the BTEC Higher National Diploma in Computing, specifically focusing on Unit 20: Applied Programming and Design Principles. It includes details about the assignment titled 'Sales Analysis System for Sampath Food City (PVT) Ltd', assessment criteria, and guidelines for submission, along with a grading rubric for evaluating student performance. Additionally, it emphasizes the importance of adhering to academic integrity and the consequences of plagiarism.

Uploaded by

89thisara
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 93

Higher Nationals

Internal verification of assessment decisions – BTEC (RQF)


INTERNAL VERIFICATION – ASSESSMENT DECISIONS

Programme title BTEC Higher National Diploma in Computing - Software Engineering

Assessor Mr. Sadeepa Internal Verifier

Unit(s) Unit 20: Applied Programming and Design Principles

Assignment title Sales Analysis System for Sampath Food City (PVT) Ltd

Student’s name Thisara Madhushanka Dayarathna


List which assessment Pass Merit Distinction
criteria the Assessor has
awarded.
INTERNAL VERIFIER CHECKLIST

Do the assessment criteria awarded match


those shown in the assignment brief? Y/N

Is the Pass/Merit/Distinction grade awarded


justified by the assessor’s comments on the Y/N
student work?
Has the work been assessed
Y/N
accurately?
Is the feedback to the student:
Give details:

• Constructive?
Y/N
• Linked to relevant assessment
Y/N
criteria?
• Identifying opportunities
for improved performance? Y/N

Y/N
• Agreeing actions?
Does the assessment decision need
Y/N
amending?
Assessor signature Date

Internal Verifier signature Date


Programme Leader signature(if
Date
required)
Confirm actioncompleted
Remedial action taken

Give details:

Assessor signature Date

Internal Verifier
Date
signature
Programme Leader
Date
signature (if required)

2 Applied Programming and Design Principles Assignment no 1


Higher Nationals - Summative Assignment Feedback Form
Student Name/ID Thisara Madhushanka Dayarathna / RE91121
Unit Title Unit 20: Applied Programming and Design Principles
Assignment Number 1 Assessor Mr. Sadeepa
31.05.2024 Date Received 1st 31.05.2024
Submission Date
submission
Date Received 2nd
Re-submission Date
submission
Assessor Feedback:

LO1. Investigate the impact of SOLID development principles on the OOP paradigm

Pass, Merit & Distinction P1 P2 M1 D1


Descripts
LO2. Design a large dataset processing application using SOLID principles and clean coding
techniques
Pass, Merit & Distinction P3 P4 M2
Descripts

LO3. Build a data processing application based on a developed design


Pass, Merit & Distinction P5 M3
Descripts

LO4. Perform automatic testing on a data processing application


Pass, Merit & Distinction P6 P7 M4 D2
Descripts

Grade: Assessor Signature: Date:

Resubmission Feedback:

Grade: Assessor Signature: Date:

Internal Verifier’s Comments:

Signature & Date:


* Please note that grade decisions are provisional. They are only confirmed once internal and external moderation has taken place and grades decisions
have been agreed at the assessment board.

3 Applied Programming and Design Principles Assignment no 1


Assignment Feedback
Formative Feedback: Assessor to Student

Action Plan

Summative feedback

Feedback: Student to Assessor

Assessor signature Date


thisara1989@hotmail.com 31.05.2024
Student signature Date

4 Applied Programming and Design Principles Assignment no 1


Pearson
Higher Nationals in
Computing
Unit 20: Applied Programming and Design Principles
Assignment 01

5 Applied Programming and Design Principles Assignment no 1


General Guidelines

1. A Cover page or title page – You should always attach a title page to your assignment. Use previous page as
your cover sheet and make sure all the details are accurately filled.
2. Attach this brief as the first section of your assignment.
3. All the assignments should be prepared using a word processing software.
4. All the assignments should be printed on A4 sized papers. Use single side printing.
5. Allow 1” for top, bottom , right margins and 1.25” for the left margin of each page.

Word Processing Rules

1. The font size should be 12 point, and should be in the style of Time New Roman.
2. Use 1.5 line spacing. Left justify all paragraphs.
3. Ensure that all the headings are consistent in terms of the font size and font style.
4. Use footer function in the word processor to insert Your Name, Subject, Assignment No, and Page Number
on each page. This is useful if individual sheets become detached for any reason.
5. Use word processing application spell check and grammar check function to help editing your assignment.

Important Points:

1. It is strictly prohibited to use textboxes to add texts in the assignments, except for the compulsory information.
eg: Figures, tables of comparison etc. Adding text boxes in the body except for the before mentioned
compulsory information will result in rejection of your work.
2. Carefully check the hand in date and the instructions given in the assignment. Late submissions will not be
accepted.
3. Ensure that you give yourself enough time to complete the assignment by the due date.
4. Excuses of any nature will not be accepted for failure to hand in the work on time.
5. You must take responsibility for managing your own time effectively.
6. If you are unable to hand in your assignment on time and have valid reasons such as illness, you may apply (in
writing) for an extension.
7. Failure to achieve at least PASS criteria will result in a REFERRAL grade .
8. Non-submission of work without valid reasons will lead to an automatic RE FERRAL. You will then be asked to
complete an alternative assignment.
9. If you use other people’s work or ideas in your assignment, reference them properly using HARVARD
referencing system to avoid plagiarism. You have to provide both in-text citation and a reference list.
10. If you are proven to be guilty of plagiarism or any academic misconduct, your grade could be reduced to A
REFERRAL or at worst you could be expelled from the course.
11. If you are proven to be guilty of plagiarism or any academic misconduct, your grade could be reduced to A
REFERRAL or at worst you could be expelled from the course.

6 Applied Programming and Design Principles Assignment no 1


Student Declaration

I hereby, declare that I know what plagiarism entails, namely to use another’s work and to present it as my own
without attributing the sources in the correct way. I further understand what it means to copy another’s work.

1. I know that plagiarism is a punishable offence because it constitutes theft.


2. I understand the plagiarism and copying policy of the Pearson UK.
3. I know what the consequences will be if I plagiaries or copy another’s work in any of the assignments for this
program.
4. I declare therefore that all work presented by me for every aspects of my program, will be my own, and where
I have made use of another’s work, I will attribute the source in the correct way.
5. I acknowledge that the attachment of this document signed or not, constitutes a binding agreement between
myself and Pearson, UK.
6. I understand that my assignment will not be considered as submitted if this document is not attached to the
attached.

thisara1989@hotmail.com
Student’s Signature: Date: 31st May 2024
(Provide E-mail ID) (Provide Submission Date)

7 Applied Programming and Design Principles Assignment no 1


Assignment Brief
Student Name /ID Number Thisara Madhushanka Dayarathna / RE91121

Unit Number and Title Unit 20: Applied Programming and Design Principles

Academic Year 2022/2023

Unit Tutor Mr. Sadeepa

Assignment Title Sales Analysis System for Sampath Food City (PVT) Ltd

Issue Date

Submission Date 31.05.2024

IV Name & Date

Submission Format:

Part 1.
Report- Submit a professional report with appropriate report formatting and guidelines followed. All the
research data should be referenced along with in-text citations using the Harvard referencing system.

Part 2
A fully functional standalone software system (command-line interface based)

Unit Learning Outcomes:

LO1 Investigate the impact of SOLID development principles on the OOP paradigm.
LO2 Design a large dataset processing application using SOLID principles and clean coding techniques.
LO3 Build a data processing application based on a developed design.
LO4 Perform automatic testing on a data processing application.

8 Applied Programming and Design Principles Assignment no 1


Assignment Brief and Guidance:

Assignment Brief
Scenario.
‘Data Labs’ is a leading software development company in Sri Lanka. They are focusing on helping
businesses to build their businesses through creative and effective solutions. Assume that you work as an
apprentice software developer for Data Labs company. As a part of your role, you have been asked to
develop a software system (command-line interface based) for the following scenario using python
programming language.

Sampath Food City (PVT) Ltd is one of the main supermarket networks in Sri Lanka. Currently, Sampath
Food City has several branches island wide. At present, transactions of each branch are recorded through a
point of sale (pos) system. At the end of each month, recorded data of each point of the sales system are
transferred to a centralized database. Top-level management of the company use the centralized data to do
the monthly sales data analysis of the whole company at the end of the month to find insights to take
managerial decisions for the company. Currently, the company uses a paper-based manual system to do
monthly sales data analysis. Some weaknesses and drawbacks that have occurred in the manual system such
as human errors leading to inaccurate information, time consuming, data redundancy, inconsistency and
difficulty to find insights affect the business performance negatively.
Therefore, the management of Sampath Food City has decided that using a customized software system
for sales data analysis is the solution for eliminating above mentioned weaknesses and drawbacks of the
existing sales data analysis process.
Assume yourself as a software developer of Data Labs (PVT) Ltd and assigned to develop a sales data
analysis system (command-line interface based) using python programming language for scenario given
above.
New system should provide following features:
• Monthly sales analysis of each branch.

9 Applied Programming and Design Principles Assignment no 1


• Price analysis of each product
• Weekly sales analysis of supermarket network
• Product preference analysis
• Analysis of the distribution of total sales amount of purchases

Develop a command-line interface-based solution for the above scenario and produce a report
covering the following tasks.

Activity 1

• Investigate the characteristics of the object-orientated paradigm, including class relationships


(inheritance, association, composition, aggregation) and evaluate the impact pf SOLID principles
(single responsibility principle, open/closed principle, Liskov’s substitution principle, interface
segregation principle and dependency inversion principle) by taking suitable examples
incorporating UML diagrams and coding samples. Your answer should include suitable examples
to evaluate the impact of SOLID principles in Object oriented Development.

• Explain how clean coding techniques can impact on the use of data structures and operations when
writing algorithms by taking suitable examples from the given scenario. Analyse each of the
creational, structural and behavioral design patterns with relevant examples.

Activity 2

• Design a large data set processing application, utilising SOLID principles, clean coding techniques,
a design pattern and data structures by providing justifications for selected design pattern and
selected data structures.
• Design a suitable testing regime for the application developed with a provision for automated
testing, selected test types and selected automatic testing tools, and provide justifications for the
selections. Refine the design to include multiple design patterns by justifying the reasons for the
inclusion of each design pattern for the given scenario.

10 Applied Programming and Design Principles Assignment no 1


Activity 3

Build a large dataset processing application based on the design produced, by using python programming
language and provide evidence for the usage of data structures and file handling techniques. Your answer
must include an assessment of how effective the use of SOLID principles, clean coding techniques and
programming patterns on the application developed. Take suitable examples from the developed application
to elaborate your answer.

Activity 4
• Examine the benefits and drawbacks of different methods of automatic testing of applications and
software systems available for automatic testing by taking examples from the developed application.
Provide an action plan to address the identified drawbacks of testing of the developed application.
• Implement automatic testing of the developed application by using selected testing tools and provide
evidence for the automatic testing. Discuss how developer-produced and vendor-provided automatic
testing tools differ for applications and software systems by taking suitable examples from the
testing of the developed application.

11 Applied Programming and Design Principles Assignment no 1


Grading Rubric
Grading Criteria Achieved Feedback

LO1 Investigate the impact of SOLID development principles on


the OOP paradigm.
P1 Investigate the characteristics of the object orientated
paradigm, including class relationships and SOLID principles.

P2 Explain how clean coding techniques can impact on the use of


data structures and operations when writing algorithms.

M1 Analyse, with examples, each of the creational, structural and


behavioral design pattern types.

D1 Evaluate the impact of SOLID development principles on object


orientated application development.

LO2 Design a large dataset processing application using SOLID


principles and clean coding techniques.
P3 Design a large data set processing application, utilising SOLID
principles, clean coding techniques and a design pattern.

P4 Design a suitable testing regime for the application, including


provision for automated testing.

M2 Refine the design to include multiple design patterns.

LO3 Build a data processing application based on a developed


design

12 Applied Programming and Design Principles Assignment no 1


P5 Build a large dataset processing application based on the design
produced.
M3 Assess the effectiveness of using SOLID principles, clean coding
techniques and programming patterns on the application
developed.
LO4 Perform automatic testing on a data processing application.
P6 Examine the different methods of implementing automatic
testing as designed in the test plan.
P7 Implement automatic testing of the developed application.

M4 Discuss the differences between developer-produced and


vendor-provided automatic testing tools for applications and
software systems.

D2 Analyse the benefits and drawbacks of different forms of


automatic testing of applications and software systems, with
examples from the developed application.

13 Applied Programming and Design Principles Assignment no 1


2019/20 BTEC Internal Verification of Assignment Brief Template
Issue Date: 29 July 2019
Owner: BTEC Assessment
DCL1 Public (Unclassified)
Version 1.0
OBSERVATION RECORD

Learner name:
Qualification:
Unit number &
title:
Description of activity undertaken

Assessment criteria

How the activity meets the requirements of the assessment criteria

Learner name:
Learner
Date:
signature:
Assessor
name:

2019/20 BTEC Internal Verification of Assignment Brief Template


Issue Date: 29 July 2019
Owner: BTEC Assessment
DCL1 Public (Unclassified)
Version 1.0
Assessor
Date:
signature:

WITNESS STATEMENT

Learner
name:
Qualification:
Unit number
& title:
Description of activity undertaken (please be as specific as
possible)

Assessment criteria (for which the activity provides evidence)

How the activity meets the requirements of the assessment


criteria, including how and where the activity took place

Witness Job
name: role:

2019/20 BTEC Internal Verification of Assignment Brief Template


Issue Date: 29 July 2019
Owner: BTEC Assessment
DCL1 Public (Unclassified)
Version 1.0
Witness Date
signature: :
Learner
name:
Learner Date
signature: :
Assessor
name:
Assessor Date
signature: :

2019/20 BTEC Internal Verification of Assignment Brief Template


Issue Date: 29 July 2019
Owner: BTEC Assessment
DCL1 Public (Unclassified)
Version 1.0
Contents
Activity 1 ............................................................................................................................. 1
1.1 Object Oriented Programming ....................................................................................... 1
1.1.1 Advantages of Object-Oriented Programming .................................................................... 2
1.1.2 Key Principles of Object – Oriented Programming............................................................. 3
1.1.3 Characteristics of the Object – Oriented Paradigm ............................................................. 9
Classes and Objects .................................................................................................................. 9
Inheritance .............................................................................................................................. 11
Association ............................................................................................................................. 11
Aggregation ............................................................................................................................ 12
Composition ........................................................................................................................... 12
1.2 SOLID Principles ......................................................................................................... 13
1.2.1 The Single Responsibility Principle (SRP) ....................................................................... 13
1.2.2 Open/Closed Principle (OCP) ........................................................................................... 15
1.2.3 Liskov Substitution Principle (LSP) .................................................................................. 16
1.2.4 Interface Segregation Principle (ISP) ................................................................................ 17
1.2.5 Dependency Inversion Principle (DIP).............................................................................. 19
1.3 Clean Coding Techniques ............................................................................................ 20
Benefits of Clean Coding ........................................................................................................... 22
Design patterns ........................................................................................................................... 30
Creational design patterns ...................................................................................................... 31
Structural Design Patterns ...................................................................................................... 37
Behavioral Design Patterns .................................................................................................... 41
Activity 2 ........................................................................................................................... 44
2.1 Design a large data set processing application ..................................................................... 44
2.1.1 Design patterns .................................................................................................................. 44
2.1.2 Exploring Effective Design Patterns in Application Development for Optimal Designing
Practices...................................................................................................................................... 45
2.1.3 Design Pattern and Data Structures ................................................................................... 46
2.2 Design a suitable testing regime for the application, including provision for automated
testing. ........................................................................................................................................ 47
2.3 Refine the Design and Include Multiple Design Patterns..................................................... 51
Activity 3 ........................................................................................................................... 53
3.1 Build a large dataset processing application based on the design produced. ....................... 53
3.2 Effectiveness of Development Principles and Patterns in our Application Design .............. 63
Activity 4 ........................................................................................................................... 65
4.1 Different methods of implementing automatic testing as designed in the test plan. ............ 65
4.2 Implement automatic testing of the developed application. ................................................. 67
4.3 Differences between developer-produced and vendor-provided automatic testing tools for
applications and software systems. ............................................................................................. 68
4.4.1 Analyse the benefits and drawbacks of different forms of automatic testing of applications
and software systems. ................................................................................................................. 69
4.4.2 Employ Selected Testing Tools ......................................................................................... 71
References .......................................................................................................................... 72
Activity 1

1.1 Object Oriented Programming

Object-oriented programming (OOP) is a way of designing software that focuses on data


in the form of objects, rather than just on functions and logic. In OOP, objects have unique
attributes and behaviours, and developers focus on these objects rather than the processes
to work with them. This method is especially useful for creating large, complex, and
frequently updated programs, like those used in manufacturing, design, and mobile apps.

Object-oriented programming makes teamwork easier because it organizes projects into


smaller, manageable parts. It also makes code reusable, scalable, and efficient. At the start,
programmers identify all the objects they need to work with and define how these objects
relate to each other using data modelling. These objects can be real-world things, like a
person with a name and address, or small programs like widgets. Each object is assigned to
a class that defines the data and methods (actions) that can manipulate it. Objects
communicate with each other through clear interfaces called messages.

Figure 1 - Object-oriented programming (OOP) system

1|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
1.1.1 Advantages of Object-Oriented Programming

Object-oriented programming (OOP) has many important benefits that make it a popular
choice for developing different kinds of software.

1. Modularity - OOP lets us break down software into smaller, manageable parts
called classes. Each class can be developed, tested, and debugged on its own,
making the development process more efficient and organized.

2. Code Reusability - In OOP, classes can be reused in different programs. Using


inheritance, new classes can use existing code, reducing the need to write repetitive
code. This makes development faster and more efficient.

3. Scalability - OOP systems can easily grow. We can add new objects and classes
with minimal changes to existing code, making OOP perfect for projects that need
to expand and evolve over time.

4. Maintainability - Because OOP is modular, maintaining and updating software is


easier. Objects are self-contained, so changes in one part of the program have little
impact on others, reducing the chance of bugs when making updates.

5. Abstraction - OOP helps developers manage complex systems by focusing on


high-level concepts and hiding detailed implementation. This allows developers to
focus on the overall design and structure of the software.

6. Encapsulation - Encapsulation protects data from external interference and misuse.


By restricting access to certain parts of an object, OOP ensures that the object's
internal state can only be changed in controlled ways through its methods.

7. Polymorphism - Polymorphism allows objects from different classes to be treated


as objects of a common superclass. This makes it easier to use a single interface for
different data types, simplifying the design of flexible and scalable systems.

8. Collaboration- OOP's structured approach makes teamwork easier by clearly


defining interfaces and responsibilities. Teams can work on different classes or
objects at the same time without conflicts, improving productivity and coordination.

9. Efficiency in Problem Solving - OOP breaks down complex problems into smaller,
manageable objects. Each object can be developed to handle a specific part of the
problem, making the problem-solving process more straightforward.

10. Real-World Modeling - OOP naturally represents real-world problems. Objects


can mimic real-world entities with attributes (data) and behaviors (methods),
making it easier to design and understand software systems that reflect real-world
processes.

2|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Object-oriented programming (OOP) is used in many software areas because it helps
handle complex systems well. For example, in software development, it's often used to
make big programs, letting teams work on different parts easily. In web development,
languages like JavaScript, PHP, Ruby, and Python use OOP to make dynamic websites
with neat code. Games also use OOP a lot to manage characters and items effectively, using
engines like Unity and Unreal Engine. Mobile apps for Android and iOS benefit from OOP
because it make development, upkeep, and growth simple. Making user interfaces (UIs) is
easier with OOP, using tools like JavaFX, Qt (C++), and Tkinter (Python).

OOP is also handy in other areas like simulations, business software, data analysis,
embedded systems, and robotics because it helps make models accurate, and systems easy
to expand and manage.

1.1.2 Key Principles of Object – Oriented Programming

Object-oriented programming (OOP) is based on a few main ideas that guide how it works.
These ideas help programmers make code that's easier to understand, organize, and use.

1. Encapsulation: Encapsulation means putting data and the methods that work on
that data together in one place. It helps keep things organized and stops other parts
of the program from messing with the data by mistake. In OOP, we bundle data
(attributes) and the actions that work on that data (methods) into a single unit or
class. This helps hide the details of how things work and protects the data from
being changed by mistake.

Figure 2 - Encapsulation

3|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 3 – Example for encapsulation (Author created)

In this example:

• We have a Car class with encapsulated attributes (__make, __model, and __speed).

• These attributes are marked as private by prefixing them with double underscores
(__), which means they cannot be accessed directly from outside the class.

• We define public methods (accelerate, brake, and get_speed) to interact with these
encapsulated attributes. These methods allow controlled access to the data,
ensuring that the internal state of the Car object is maintained properly.

• When creating a Car object (my_car), we provide the make and model as
arguments.

• We use the accelerate and brake methods to modify the car's speed and the
get_speed method to retrieve the current speed.

2. Inheritance: Inheritance is like passing down traits in families. It lets new types of
things inherit characteristics and behaviors from existing types. This saves time
because we can reuse what's already been made. Inheritance allows a new class
(subclass) to inherit attributes and methods from an existing class (superclass). This
helps us reuse code and create relationships between classes, where subclasses can
have their own special features but also share features with their parent class.

4|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 4 – Inheritance

Figure 5 – Example for Inheritance (Author created)

5|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
In this example:

• We have a parent class Animal with an attribute species and a method speak(). The
speak() method is defined but not implemented (pass) in the parent class.

• We define two child classes Dog and Cat, both inheriting from the Animal class.
They have their own attributes (breed) and implement the speak() method specific
to each type of animal.

• The __init__() method of each child class calls the constructor of the parent class
using super().__init__(), initializing the species attribute inherited from Animal.

• We create objects (dog and cat) of the child classes and access their attributes
(species and breed) as well as the overridden speak() method to get the sound each
animal makes.

3. Polymorphism: Polymorphism means treating different types of things the same


way. It lets us use one interface for different types of objects, which makes the code
more flexible and easier to use. Polymorphism allows objects of different classes to
be treated as if they were the same type of object. This makes our code more flexible
and adaptable because we can use different objects interchangeably.

Figure 6 – Polymorphism

6|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 7 – Example for Polymorphism (Author created)

In this example:

• We have a parent class Animal with a method speak(). This method is defined but
not implemented (pass) in the parent class.

• We define three child classes Dog, Cat, and Cow, each inheriting from the Animal
class. They implement their own speak() method specific to each type of animal.

• We define a function make_animal_speak(animal) that takes an Animal object as


an argument and calls its speak() method.

• We create objects (dog, cat, and cow) of different classes and pass them to the
make_animal_speak() function.

• Despite the objects being of different types (Dog, Cat, Cow), they all have a speak()
method. When we call make_animal_speak() with each object, it invokes the
respective speak() method associated with that object's class.

7|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
4. Abstraction: Abstraction hides complicated details and only shows what's
important. It's like driving a car without knowing how the engine works – we don't
need to know every detail to use it effectively. Abstraction hides the complex details
of how things work and shows only the important parts. This helps us work with
high-level ideas and concepts in our programs.

Figure 8 – Abstraction

Figure 9 – Example for Abstraction (Author created)

8|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
In this example:

• We have an abstract class Shape that defines two abstract methods area() and
perimeter(). These methods serve as an interface for any shape class to implement.

• We define two concrete classes Rectangle and Circle that inherit from the Shape
class. These classes implement the area() and perimeter() methods according to
their specific shapes.

• We have a function calculate_shape_info(shape) that takes any object of a class


that implements the Shape interface. This function can calculate and print the area
and perimeter of any shape without needing to know the details of each shape's
implementation.

• We create objects of different shapes (rectangle and circle) and pass them to the
calculate_shape_info() function. Despite their differences in implementation, the
function can work with any shape object because they all adhere to the common
Shape interface.

1.1.3 Characteristics of the Object – Oriented Paradigm

Classes and Objects


Classes are like blueprints for making objects, which are like the actual things. Classes
define what an object can do and what it's made of. In OOP, everything is an object. Classes
define what an object will be like what attributes it will have and what actions it can
perform. They help organize and structure our code. Objects are like real-world things that
have both characteristics (attributes) and actions they can perform (methods). They help us
represent and interact with things in our programs.

Figure 10 - Classes and Objects

9|Page
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 11 – Example for Class & Object (Author created)

In these examples:

• We define classes (Student) with attributes and methods.

• We create objects (student1, student2) of these classes, providing initial values for
their attributes.

• We access attributes and methods of the objects using dot notation


(object_name.attribute or object_name.method()).

• We modify attributes using methods defined within the class.

• We can create multiple objects of the same class, each with its own set of attribute
values.

10 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
In object-oriented programming, classes work together in different ways to show how
objects from those classes connect and depend on each other. These connections help define
how the parts of a program fit together and cooperate.

Inheritance
Think of this as a family tree. A child class (subclass) inherits traits (attributes and methods)
from a parent class (superclass). For example, if we have a class called Animal, a class
called Dog can inherit from it. This means Dog is a type of Animal and gets all the basic
features of an Animal.

Figure 12 - Inheritance (Author created)

Association
This is a basic connection where one class uses or knows about another. For example, a
Teacher class might be associated with a Student class because teachers teach students,
but they are separate entities and don't own each other.

Figure 13 - Association (Author created)


11 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Aggregation
This is a special type of association showing a whole-part relationship. The whole can exist
without the part. For example, a Library contains Books. The books are part of the library,
but they can also exist outside of it.

Figure 14 - Aggregation (Author created)

Composition
This is a stronger form of aggregation. Here, the parts cannot exist without the whole. For
example, a House is composed of Rooms. If the house is destroyed, the rooms cease to
exist.

Figure 15 – Composition (Author created)

12 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
1.2 SOLID Principles

The SOLID principles are five key guidelines that help make software easier to understand,
flexible, and maintain. Each principle focuses on a different part of designing object-
oriented software, helping to create a codebase that is strong and easy to expand. By
following these principles, we can build software that is easier to manage, extend, and keep
in good shape.

Figure 16 – SOLID principles

1.2.1 The Single Responsibility Principle (SRP)

The Single Responsibility Principle (SRP) means that a class should only have one job or
reason to change. This keeps each class focused on just one task, making the system easier
to understand and manage. When classes have a single purpose, changes to one feature will
only affect the relevant class, reducing the chance of causing problems elsewhere.

Single Responsibility Principle (SRP) by separating the User class and the UserRepository
class.

13 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
User Class

The User class is responsible for user-related tasks, such as storing user information.

UserRepository Class

The UserRepository class is responsible for handling database operations related to users.

Figure 17 – User class and the UserRepository class. (Author created)

14 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
1.2.2 Open/Closed Principle (OCP)

The Open/Closed Principle (OCP) means that we should be able to add new features to our
classes, modules, or functions without changing their existing code. This helps keep our
system easy to expand and maintain, reducing the chances of creating bugs when adding
new features.

Without OCP

Suppose we have a PaymentProcessor class that handles different types of payments.


Initially, it only supports credit card payments. To add support for PayPal payments, we
need to modify the PaymentProcessor class, which violates the OCP.

With OCP
To adhere to the Open/Closed Principle, we can use inheritance or composition to extend
the functionality without modifying the existing code.

First, define an interface or abstract class for payment processing

Next, create concrete classes for each payment type

15 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Finally, we can use these classes without changing the existing PaymentProcessor interface

Figure 18 – Example for with OCP & Without OCP (Author created)

1.2.3 Liskov Substitution Principle (LSP)

The Liskov Substitution Principle (LSP) means that we should be able to replace a parent
class with a child class without breaking the program. This principle ensures that a subclass
can be used in place of its parent class without changing how the program works.

Imagine we have a base class called Bird with a method fly. An Ostrich is a type of Bird,
but it cannot fly. If a piece of code expects all Bird objects to be able to fly, using an Ostrich
instead would break the code, which violates the Liskov Substitution Principle.

Figure 19 – Violation of LSP (Author created)

A FlyingBird is a type of bird that can fly, while an Ostrich is a type of bird that cannot
fly. Code that requires flying birds can use FlyingBird directly, ensuring it never tries to
make a bird fly that can't.

16 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 21 – Adhering to LSP (Author created)

In this redesign,
• Bird is a base class for all birds.
• FlyingBird is a subclass that can fly.
• Ostrich is a subclass that does not have a fly method.

The let_flying_bird_fly function only accepts FlyingBird objects, making sure it only
works with birds that can fly. This design follows the Liskov Substitution Principle because
using a FlyingBird instead of a Bird doesn't break the program.

1.2.4 Interface Segregation Principle (ISP)

The Interface Segregation Principle says that if something doesn't need certain features, it
shouldn't have to deal with them. It's like having a phone that only does what we need it to,
without extra stuff we don't use. This makes things easier to understand and keeps
everything neat and tidy.

Imagine we have a class that requires too many responsibilities. If a client only needs a part
of those responsibilities, it's better to create smaller, more specific interfaces for each
responsibility. This way, clients only depend on the methods they actually use.

Let's consider an interface Worker that has both work and eat methods. A robot can work
but doesn't eat, while a human worker does both.

17 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 22 – Violation of ISP (Author created)

the RobotWorker class is forced to implement the eat method, which it does not need,
leading to a NotImplementedError. Now, let's split the Worker interface into two smaller
interfaces Workable and Eatable.

Figure 23 – Adhering to ISP (Author created)

18 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
1.2.5 Dependency Inversion Principle (DIP)

The Dependency Inversion Principle says that the important parts of a system shouldn't rely
too much on the smaller parts. Instead, they should both rely on general ideas or plans. This
makes it easier to change things around without causing big problems. It's like how a team
works better when everyone focuses on the big picture instead of tiny details.

Let's consider a class Switch that controls a Light. The Switch class directly depends on
the Light class.

Figure 24 – Violation of DIP (Author created)

the Switch class directly depends on the Light class, violating DIP. If we want to switch
to a different type of device, like a fan, we would have to modify the Switch class. Now
we introduce an abstract Switchable interface and make both Light and Fan implement it.

Figure 25 – Adhering to DIP (Author created)

19 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
In this redesign,
• Both Light and Fan implement the Switchable interface.
• The Switch class depends on the abstract Switchable interface, not on specific
implementations like Light or Fan.

1.3 Clean Coding Techniques

In software development, "clean code" means writing code that's easy to understand,
follow, and change. It's like writing a clear and organized story rather than a confusing
jumble of words. When code isn't clean, even small changes can cause big problems,
making it hard to fix or add new features.

The Clean Code Developer School teaches a method called Clean Analysis and Clean
Design, which focuses on planning and designing code well from the start, whether it's a
new project or an existing one. They also promote working closely with customers and
being flexible, like in agile methods, to learn and adapt quickly. The goal is to avoid
building up "technical debt" problems that pile up and become harder to fix over time.

Though it might take more effort upfront, writing clean code saves time and money in the
long run because it's easier to maintain and extend. So, clean code isn't just good for the
technical side of things, It's smart economically too.

Meaningful Names
When we write code, give things names that tell us what they're for. Whether it's a variable,
a function, or a class, its name should make it clear what it does. Imagine reading a story
where characters have names like "Person A" or "Thing B" – it wouldn't make much sense!
Similarly, in code, if we name something like "x" or "temp," it doesn't tell us anything about
what it's doing. But if we name it "userInput" or "calculateTotal," suddenly it's much easier
to understand what's going on. So, make sure our names are clear and help explain what
each part of these code does.

20 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Keep Functions Small
Make sure functions aren't too long or complicated. Each function should do just one thing,
and it should do it really well. Think of it like following a recipe, we wouldn't want a recipe
with a hundred steps all crammed into one Instead, each step focuses on just one part of
making the dish. Similarly, in our code, each function should have a clear purpose and not
try to do too much. Aim for functions that we can see all at once on our computer screen
and try to keep them focused on just one job. That way, our code stays organized and easy
to understand.

Add Comments
It's a good idea to add comments here and there to explain things that might be tricky to
understand. But try to write our code in a way that's clear and easy to follow without
needing too many comments. As per the above example on recipe, we might add a note to
explain a tricky step, but most of the time, the instructions should be clear enough on their
own. So, aim for code that's easy to read without comments, but don't be afraid to add them
when we need to explain something important.

Avoid Code Duplication


Copying and pasting code might seem like a quick fix, but it can cause problems later on.
When we have the same code in multiple places, it's harder to keep track of changes, and
it's easier for bugs to sneak in. Instead, try to find patterns in our code and create reusable
pieces, like functions or classes, to do the job. This keeps our code organized and easier to
maintain. ( "Don't Repeat Yourself" - DRY – this means we should avoid duplicating code
whenever possible. It’ll help to save time and headaches in the long run.

SOLID Principles
When we're building software using object-oriented design, it's helpful to follow a set of
principles called SOLID that we discussed in previous section. These principles are like
guidelines that help us write code that's easier to work with, change, and maintain over time

Testing
It's important to test our code in random time to make sure it works correctly. Automated
tests are like little checks that run automatically to make sure our code does what it's
supposed to do. We can think of them like quality control checks in a factory, they help
catch any mistakes or problems before they cause bigger issues.

Formatting and Consistency


When we're writing code, it's important to keep things neat and tidy. That means using the
same style and formatting rules everywhere in our code. It's like making sure all the pages
in a book have the same font and spacing – it just looks better and makes things easier to
read.

21 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Error Handling
Handling errors in our code is like driving carefully over bumps in the road instead of
crashing. It means expecting problems and having plans to deal with them without making
our program crash or act weird. This could mean catching errors and dealing with them in
a smart way. It's also important to explain errors clearly, like figuring out what's wrong
with a broken appliance by looking closely. Avoid giving vague error messages or ignoring
problems altogether, like trying to fix a health issue without knowing what's going on. By
dealing with errors well and explaining them clearly, our code becomes easier to fix and
understand, like having clear signs on a well-lit path that helps us navigate through
obstacles.

Version Control
Think of version control, like Git, as a storybook for our code. It keeps track of every
change we make, so we can see how our code has evolved over time. When we commit
changes regularly, it's like saving different versions of our story. And just like leaving notes
in our storybook to explain each update, clear commit messages explain what we changed
in our code. By using version control and committing often, we can manage our code's
history, work with others, and understand changes easily, kind of like writing a story with
a team where everyone knows what's happening.

Refactoring
Refactoring our code is like tidying up our room regularly to keep it organized and clean.
It involves restructuring our code to make it easier to understand, read, and maintain. Just
like how we might rearrange our furniture or declutter our space to make it more functional,
refactoring improves the structure of our code. It's an ongoing process, similar to how we
keep improving our room layout as we learn more about what works best for us. By
regularly refactoring our code, we ensure that it stays neat and efficient, making it easier to
work with and adapt to changes over time.

Benefits of Clean Coding


Creating a Python command-line interface for Sampath Food City's sales data analysis
system means writing code that's easy to read, organized, and efficient. This involves
making sure functions and methods are clear and focused, using data structures effectively,
and keeping the code neat and consistent. We need to avoid messy code and focus on
keeping things simple and understandable. By doing this, we can make sure the code is
easy to work with and doesn't have any mistakes or confusing parts. Regularly improving
the code through updates and changes will help keep it running smoothly and accurately
over time, which is crucial for the success of Sampath Food City's sales analysis system.

Readability
Clean code is like a clear road map. It's easy to understand where we're going and why.
This helps developers work together better and saves time when they need to check or
update the code later. When the code is neat and tidy, it's easier to fix problems or add new
stuff without accidentally messing up other parts. When everyone can understand the code
easily, it makes working together smoother and faster. In the scenario provided, readability
is crucial for ensuring that the code is easily understandable by developers, facilitating
collaboration, maintenance, and future enhancements.

22 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 26 – Without Clean Code (Author created)

• The function and variable names are abbreviated and unclear (cap, d, t, c, r), making
it hard to understand the purpose of the code at a glance.
• All logic is crammed into a single function, which makes the code harder to read
and maintain.

Figure 27 – With Clean Code (Author created)

• Clear and descriptive names make the purpose of each function and variable
immediately apparent.
• The code is structured and modular, with each function handling a specific part of
the task.
• Error handling and type checking improve the robustness and readability of the
code.

Maintainability
Maintainability means that when the code is clean and well-organized, it's easier for
developers to find and fix mistakes, add new features, or change things without causing
more problems. It's like having a well-kept garden – we can see what needs attention and
make changes without damaging the whole thing. This saves time and money in the long
run because we don't have to spend as much time fixing things or dealing with unexpected
issues. Let's compare an example of calculating the monthly sales of each branch with and
without clean coding principles for maintainability as per our scenario.

23 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 28– Without Clean Code (Author created)

Figure 29 – With Clean Code (Author created)

• The calculate_total_and_count function can be reused or adapted for different


calculations, reducing code duplication.
• Clear and modular functions make it easier to update or extend functionality without
affecting other parts of the code.
• Each function has a single responsibility, making the codebase easier to navigate
and maintain.

Scalability
Scalability means that clean code is like building with Lego blocks – we can add more
blocks as our project grows without everything falling apart. This makes it easy to add new
features or make changes without making a mess. When code is well-structured and
organized, developers can add new pieces without making the existing ones messy or
complicated. It's like building a bigger house on a strong foundation, everything stays
sturdy and in place as the project gets bigger. This makes it easier for developers to work
on the code and keep it running smoothly as the project grows.

For a sales data analysis system like the one for Sampath Food City, scalability ensures that
the system can handle increasing amounts of sales data from multiple branches and more
complex analyses without performance degradation.

Figure 30– Without Clean Code (Author created)


24 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 31 – With Clean Code (Author created)

• This modular design is more scalable because we can easily extend the
functionality. For instance, if we need to calculate the average price for different
categories of products, we can reuse the calculate_total_and_count function without
modifying the core logic of calculate_average_price.

Reduced Errors
Reduced errors mean that clean code is like clear instructions. it's easy to understand what
needs to be done, which reduces the chance of making mistakes. When the code is clear
and easy to follow, developers are less likely to get confused or make errors while working
on it. This leads to higher-quality code with fewer bugs in the end product. It's like
following a recipe with clear steps – when everything is laid out clearly, it's harder to mess
up the final dish.

Figure 32– Without Clean Code (Author created)

Figure 33 – With Clean Code (Author created)

25 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
• In the clean code example, data: List[Tuple[str, float]] clearly defines the expected
input type, reducing the risk of passing incorrect data types.
• The clean code checks if the price is of the correct type (int or float) before adding
it to the total, and it skips and logs a message for invalid entries.
• The logic is more explicit and easier to understand, reducing the likelihood of
introducing errors when modifying or extending the code.
• The clean code ensures that if no valid prices are found, the function returns 0.0
instead of causing a division by zero error.

Reusability for Faster Development


Clean code means breaking big tasks into smaller ones that can be easily reused. This makes
it quicker to understand, test, and work with. Instead of writing the same thing over and
over, we can use what's already there, saving time and energy. Also, making handy tools
or functions that do common things helps keep everything consistent and speeds up
development. Clean code hides all the complicated stuff behind simple instructions, making
it easier to build on later. Plus, when we've tested something well once, we can trust it to
work every time we use it. And as our project grows, we can add or change things without
having to start from scratch. All these things together make coding faster and easier, and
our projects more flexible and adaptable.

Figure 34 – Without Clean Code (Author created)

• The logic for calculating averages is duplicated in two separate functions.


• Any changes or bug fixes would need to be applied in multiple places, slowing
down development.

26 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 35 – With Clean Code (Author created)

• The logic is centralized in reusable functions, making it easy to extend or modify.


• The use of clear names and modular functions makes the code easier to understand
and maintain.
• Adding new features or making changes can be done quickly since the reusable
functions handle the core logic.

Enhanced Collaboration
Writing clean code is like having a well-organized toolbox. We can quickly find the right
tool for the job, which speeds up the work. When the code is clean and easy to understand,
developers spend less time trying to figure out what's going on and more time actually
working on it. This means projects get finished faster, and the software can be released
sooner. We can get to our destination much faster when there are no obstacles in the way.

Figure 36 – Without Clean Code (Author created)

• The function calculate_average_price calculates the average price of products but


lacks clarity in its implementation.
• Variable names like total and count are not descriptive, making it harder for other
developers to understand the code.
27 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
• The lack of type hints and docstrings makes it challenging for other developers to
know the expected inputs and outputs of the function.

Figure 37 – With Clean Code (Author created)

• The function calculate_average_price has clear and descriptive variable names


(total_price instead of total).
• Type hints (List[Dict[str, float]]) provide clarity on the expected input type,
improving readability and reducing ambiguity.
• A docstring provides information about the function's purpose and usage, aiding
other developers in understanding and utilizing the function effectively.

Adaptability
Clean code is like a flexible building. It can easily be reshaped or expanded to fit new
requirements or technology. By following best practices and design principles, developers
can adjust or add to the existing code without worrying about breaking it. This ensures that
the software stays flexible and can adapt to changing needs over time. It's like having a
house that can be remodeled without tearing down walls – the structure remains strong, and
we can make changes confidently as needed. This adaptability is crucial for keeping the
software responsive to evolving technology and user requirements.

Figure 38 – Without Clean Code (Author created)

• The function calculate_average_price calculates the average price of products, but


it's hardcoded to work only with a specific data structure (list of dictionaries).
• If the structure of the products data changes in the future (e.g - nested dictionaries,
additional fields), the function may no longer work correctly without modifications.

28 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 39 – With Clean Code (Author created)

• The function calculate_average_price is designed to accept a list of dictionaries


(List[Dict[str, float]]) as input, providing flexibility in the structure of the products
data.
• By using type hints and a clear function signature, the code is adaptable to changes
in the data structure without requiring modifications to the function itself.
• This clean code approach ensures that the function remains adaptable to future
changes, making it easier to maintain and extend as the project evolves.

Improved Debugging
Clean code is like a well-organized library. Everything is labeled clearly and easy to find.
With descriptive names, clear structure, and helpful comments, developers can quickly
understand what each part of the code is doing. This makes it much easier to find and fix
problems when they arise. It's like having a map to guide us through a maze – we can
quickly pinpoint where things went wrong and trace the path to the solution. This speed up
the debugging process and helps developers resolve issues more efficiently, keeping the
software running smoothly.

Figure 40 – With Clean Code (Author created)

• In the original code, the function calculate_average_price calculates the average


price of products without validating the data integrity.
• If there is invalid data (e.g., non-numeric price), the function will raise an exception
during execution, making it challenging to identify the cause of the error.

29 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 41 – With Clean Code (Author created)

• The improved version of the function calculate_average_price includes error


checking to ensure that the price of each product is a numeric value.
• If an invalid price is encountered, the function prints a message indicating the issue
and skips the product, preventing the code from crashing.
• This clean code approach improves debugging by providing informative error
messages and handling invalid data gracefully, making it easier to identify and
resolve issues during development.

Design patterns

Design patterns are like ready-made templates for solving common problems in software
design. They're not specific pieces of code we can copy and paste, but more like general
ideas or concepts. When we follow a pattern, we're basically using a blueprint to create a
solution that fits our program's needs. While patterns are often compared to step-by-step
recipes (like cooking we talk earlier), they're more like outlines that give us the main idea
and let us figure out the details ourself. And even if we use the same pattern in different
programs, the actual code we write might be different each time.

30 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Creational design patterns

Figure 42 – Creational design patterns

Creational design patterns are all about making it easier to create objects in software. They
help hide the complicated stuff about how objects are made, so we can focus on using them
instead. These patterns handle things like making sure there's only one instance of a class,
separating how an object is created from how it's used, and giving we ways to create objects
without knowing exactly what kind they are. There are different types of creational patterns,
like Singleton, Factory Method, Abstract Factory, Builder, and Prototype, each with its own
way of tackling these problems.

1. Singleton
The Singleton pattern ensures that only one instance of a class exists throughout the entire
application, regardless of how many times we try to create objects of that class. It achieves
this by controlling the creation process through a special method or property in the class.
This method checks if an instance of the class already exists; if it does, it returns that
instance, otherwise, it creates a new instance and returns it. This pattern is handy in
situations where having multiple instances of a class could lead to problems, like managing
resources or maintaining a global state. By limiting instances to one, Singleton provides a
straightforward way to access this single instance from anywhere in the application,
ensuring consistency and centralized control.

Figure 43 – Singleton pattern (Author created)

31 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
In this example, the Singleton class is used to calculate the square of a number. The
get_instance() method ensures that only one instance of Singleton is created, and the
calculate_square() method calculates the square of the number set using the set_number()
method.

2. Factory Method Pattern


The Factory Method pattern is a way to create objects in programming where subclasses
decide what type of object to make. It works by having a method in a class that acts as a
factory to make objects. Subclasses can change this method to make different kinds of
objects. This helps make code flexible and easy to change without having to rewrite
everything. It's useful when we need different types of objects or when making objects is
complicated.

Figure 44 – Factory Method (Author created)

We have an abstract class Animal representing the product, with concrete subclasses Dog
and Cat. We also have an abstract class AnimalFactory representing the creator, with
concrete subclasses DogFactory and CatFactory. Each factory creates a specific type of
animal. This way, we can create instances of different animals without needing to know
their specific classes, promoting flexibility and loose coupling.

32 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
3. Abstract Factory Pattern
The Abstract Factory pattern is like a blueprint for creating groups of related objects
without having to know exactly what they are. It's like having a menu where we can choose
different options, but we don't need to know how each option is made. There are two main
parts: the blueprint (abstract factory) and the actual making (concrete factories). The
blueprint says how to make each object, while the concrete factories are the ones actually
making the objects. People using this pattern can just ask for what they need without
worrying about the details of how it's made. It's handy for things like creating different
parts of a computer program that all need to work together smoothly, making it easier to
change or add new parts later on.

33 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 45 – Abstract Factory pattern (Author created)

We have abstract product classes Fruit and Vegetable, along with their concrete
implementations for different types of fruits and vegetables. We also have an abstract
factory SectionFactory with methods for creating fruits and vegetables, and concrete
factory classes ProduceFactory and DairyFactory that implement these methods to create
products from the produce section and dairy section of the supermarket, respectively.
Finally, the client code demonstrates how to use the factories to create products from
different sections of the supermarket and display their names.

4. Builder Pattern
The Builder pattern is like having a blueprint for building something complicated. It helps
in creating complex objects by breaking down the construction process into smaller,
manageable steps. Instead of building everything all at once, we build the object piece by
piece, following a specific order. This pattern is handy when we need to create different
versions of the same object, as it keeps the construction process organized and separate
from the final result.

34 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 46 – Builder pattern (Author created)

35 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
This code demonstrates the Builder pattern by creating two types of pizzas (Margherita and
Pepperoni) using different builders. Each builder implements the construction process for
its respective pizza type, and the director class orchestrates the process to create the final
pizzas. Finally, the pizzas are displayed to show their attributes.

5. Prototype Pattern

The Prototype pattern is like making a copy of something we already have, rather than
starting from nothing. It helps in creating new things by copying an existing one, which
can be quicker and easier, especially when the thing we're making is complex. Instead of
building everything from scratch each time, we can use a prototype as a template and make
copies of it when we need something similar. This way, we save time and effort, and we
also keep things consistent because all the copies are based on the same original.

Figure 47 – Prototype pattern (Author created)

We have a prototype class CarPrototype with a clone method that serves as the interface
for cloning. We then have a concrete prototype class Car representing a car object with
attributes for brand and model. The clone method in the Car class creates a deep copy of
the car object. Finally, in the client code, we create new car objects by cloning the prototype
and display their details.

36 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Structural Design Patterns

Figure 48 – Structural design patterns

Structural design patterns are a type of design blueprint that help organize and connect
objects in software systems. They focus on how objects work together to create larger
structures and relationships. These patterns make it easier to understand and modify the
system by addressing concerns like how objects are composed, how interfaces are defined,
and how classes inherit from each other. Essentially, they provide solutions for building
software in a way that is flexible, reusable, and easy to scale. Think of them as templates
that guide developers in designing clear relationships between different parts of the system,
ensuring that changes in one part don't cause problems elsewhere.

1. Adapter pattern
The Adapter pattern helps different things that don't speak the same language to work
together smoothly. It's like a translator between two people who speak different languages,
making sure they understand each other. For example, imagine a music player that only
knows how to play one type of music file, but we want it to play a different type. The
Adapter pattern acts like a translator, allowing the music player to understand and play the
new type of file without any confusion.

37 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 49 – Adapter pattern (Author created)

This code defines three classes: MP3Player, WAVPlayer, and AudioAdapter. The
AudioAdapter class acts as a bridge between MP3Player and WAVPlayer, allowing
them to play audio files of different formats using a unified play method. We can create an
instance of MP3Player, create an adapter with it, and then use the adapter to play MP3
files.

2. Bridge pattern

The Bridge pattern is a way of organizing code so that different parts can change
independently. It's like building a bridge between two separate things so they can work
together without being too closely connected. For example, imagine we have a program
that can draw shapes, but we want it to be able to draw shapes in different colors. The
Bridge pattern would help us keep the drawing part separate from the coloring part, so we
can change one without affecting the other. It's a helpful way to make our code more
flexible and easier to work with, especially when we expect things to change often.

38 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 50 – Bridge pattern (Author created)

We have an abstraction Shape, which represents a shape that can be drawn with a color.
We also have concrete implementations RedColor and BlueColor, which represent
different colors. The refined abstractions Circle and Square extend the Shape class and
implement the draw method to draw themselves in the specified color. The Bridge pattern
allows us to change the color of a shape without modifying its class by passing different
color objects to the shapes.

3. Composite pattern
The Composite pattern is like organizing objects into a tree, where each object can either
be a single item or a group of items. It helps in treating individual items and groups of items
in the same way, making it easier to work with complex structures. For example, in a file
system, a folder can contain both files and other folders. The Composite pattern allows us
to perform operations like listing, searching, or deleting items, whether they are individual
files or folders with more items inside. It's like having a unified way to handle both
individual elements and collections of elements in a structured manner.

39 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 51 – Composite pattern (Author created)

We have a Product interface with a name and price. The Department class represents
composite components that can contain other products or departments. Departments can
add, remove, and operate on their children, whether they are Product objects or other
Department objects. Finally, we create a composite structure with nested departments and
products and call the operation method to display the entire inventory.

4. Decorator pattern
The Decorator pattern is like adding layers of wrapping paper around a gift. It lets us add
extra features to an object without changing its core structure. Imagine we have a plain
cake, and we want to decorate it with frosting, sprinkles, and icing. With the Decorator
pattern, we can add each decoration separately without changing the cake itself. Similarly,
in programming, we can add new features or behaviors to objects without changing their
original code. This pattern is useful when we want to customize or extend the functionality
of objects dynamically, like adding new options to a menu without altering the existing
items.

40 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 52 – Decorator pattern (Author created)

Coffee is the component interface, SimpleCoffee is a concrete component, and


CoffeeDecorator is the decorator interface. Milk and Sugar are concrete decorators that
add additional functionality to the coffee. When we create a simple coffee object and add
decorators to it, the cost of the coffee gets updated accordingly.

Behavioral Design Patterns

Figure 53 – Behavioral Design Patterns

41 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Behavioral design patterns are a group of design patterns that help objects in a program to
talk to each other and work together better. They're like rules that guide how different parts
of a program should communicate to get things done efficiently. These patterns make it
easier for developers to manage how objects interact and share tasks, making the program
more flexible and easier to maintain. They provide solutions to common problems in
communication and teamwork between objects, giving developers a roadmap for building
software that works well together.

Observer pattern
The Observer pattern is like a messaging system where one object sends out messages, and
other objects listen for those messages. Imagine we have a group chat, and whenever
someone sends a message, everyone else in the group gets notified. That's how the Observer
pattern works. In software, it's used when one part of the program needs to tell other parts
about changes it's going through. For example, if we're building a weather app, the
Observer pattern would let us update the temperature display whenever the weather
changes without having to constantly check for updates. It's a handy way to keep different
parts of a program in sync without them having to know too much about each other.

Figure 54 – Observer pattern (Author created)

42 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
The Subject class represents the supermarket, and the Observer class represents different
roles in the supermarket, such as cashiers, stock managers, and customers. When a new
product is added to the inventory (notify method is called), all observers are notified
(update method is called), and they react accordingly. For instance, the cashier rings up
the product, the stock manager restocks it, and the customer buys it.

Strategy pattern
The Strategy pattern lets us pick different ways of doing something while our program runs.
It works like having different tools in a toolbox, and we can choose which one to use
depending on what we need. So instead of having just one way to do things, we can switch
between different methods easily, making our code more flexible and easier to change later
on.

Figure 55 – Strategy pattern (Author created)

The ShoppingCart class represents the context, and it takes a DiscountStrategy object as
a parameter. Depending on the type of customer (regular or premium), we can pass different
discount strategies to the ShoppingCart object. The RegularCustomerDiscount and
PremiumCustomerDiscount classes represent different strategies for calculating
discounts.

43 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Activity 2

2.1 Design a large data set processing application

2.1.1 Design patterns


The Single Responsibility Principle (SRP)

The Single Responsibility Principle (SRP) is a key idea in software design that says each
part of a program should do just one thing. This means breaking down a big, complex
system into smaller, simpler pieces, each handling a specific task. For example, in a system
that processes data, we might have one part for getting the data, another for processing it,
and a third for sending it out. By following SRP, developers make their code easier to
understand, maintain, and test. When each part of the code has a clear job, updating or
changing one part won’t mess up the others. This makes the whole system more stable and
flexible.

The Open/Closed Principle (OCP)

The Open/Closed Principle (OCP) is a guideline in software design that says software
components should be open for adding new features but closed to changing existing code.
This means we can add new functions without altering what already exists. By designing
parts of the system to be modular and easy to extend, developers can add new features later
without breaking the existing code or causing new bugs. To achieve OCP, developers often
use techniques like inheritance, composition, and dependency injection, which help create
flexible and reusable code. Following OCP makes software more adaptable and easier to
maintain and scale, since new features can be added smoothly without messing up the
current system.

The Liskov Substitution Principle (LSP)

The Liskov Substitution Principle (LSP) is an important idea in object-oriented design. It


says that objects of a subclass should be able to replace objects of the superclass without
affecting how the program works. This means that if we have a class and its subclass, we
should be able to use the subclass anywhere we use the superclass, and the program should
still work correctly. Following LSP ensures that our class hierarchies are flexible and easy
to maintain. If we break LSP, our program can behave unexpectedly and have bugs, because
the assumptions about the superclass might not hold true for the subclass. To avoid this, it's
crucial to design our classes so that the subclass maintains the behavior expected of the
superclass, ensuring everything works smoothly and correctly.

The Interface Segregation Principle (ISP)

The Interface Segregation Principle (ISP) is a key concept in software design that suggests
creating small, specific interfaces tailored to the needs of different clients. Instead of having
one large interface with many methods, ISP recommends breaking it down into smaller,
more focused interfaces. This way, each client only interacts with the methods it actually
44 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
needs. Following ISP helps avoid forcing clients to deal with unnecessary methods,
reducing complexity and making the system more modular and flexible. By designing
interfaces that only include what a client needs, the code becomes more intuitive, easier to
understand, and simpler to maintain. This approach minimizes the risk of unintended side
effects, leading to a more reliable and maintainable codebase.

The Dependency Inversion Principle (DIP)

The Dependency Inversion Principle (DIP) is a crucial idea in software design that helps
decouple modules by using abstractions. DIP suggests that high-level modules shouldn't
depend on low-level modules. Instead, both should depend on abstractions or interfaces.
By coding to interfaces rather than specific implementations, developers can make their
systems more flexible and easier to extend or change. DIP also promotes techniques like
dependency injection to manage dependencies and keep modules loosely connected.
Following DIP leads to software that is easier to understand, maintain, and adapt, resulting
in more robust and versatile systems.

2.1.2 Exploring Effective Design Patterns in Application Development for


Optimal Designing Practices

Structural design patterns help us use an existing class's interface in a new way, add new
responsibilities on the fly, and organize objects into tree structures to show part whole
relationships. Behavioural design patterns are great for systems where one event needs to
notify many objects, creating a one-to-many relationship. Strategy patterns keep all related
algorithms together, making them easy to swap out. Command patterns let us log and
manage different requests, allowing clients to handle various requests easily. The Model-
View-Controller (MVC) architecture splits an application into three parts.

• Model (data)
• View (user interface)
• and Controller (logic)

Using design patterns helps build scalable, maintainable, and flexible systems by offering
reusable solutions to common software design problems. Some common design patterns
are Factory Method, Abstract Factory, Adapter, Decorator, Composite, Command, and
MVC.

Creational design patterns, like Singleton, ensure there's only one instance of a class and
provide a global access point. The Factory Method pattern lets subclasses decide which
type of object to create. Abstract Factory patterns create families of related objects without
specifying their exact classes. The Repository pattern provides a way to access domain
objects using a collection-like interface, acting as a mediator between the domain and data
layers.

Dependency Injection (DI) allows a class to get the objects it depends on from outside,
making the class easier to test and configure.

45 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
2.1.3 Design Pattern and Data Structures

Choosing the right design patterns based on specific problems is key to developing
adaptable, scalable, and maintainable software. Design patterns offer reusable solutions and
promote best practices, helping developers create more robust, maintainable, and scalable
applications.

When designing a program, choosing the right design patterns is important and depends on
several factors. These include understanding the problem We're trying to solve, as well as
considering scalability, maintainability, flexibility, user interface design, data access,
integration with external libraries or services, performance, and future expansion.

• Abstract Factory pattern


• Dependency Injection pattern
• Observer pattern
• Model-View-Controller (MVC) pattern
• Repository Pattern
• Facade pattern
• Flyweight pattern

Understanding the problem domain is crucial for selecting design patterns that address
specific needs. For scalability and maintainability, patterns like Abstract Factory, Factory
Method, and Singleton are beneficial. To ensure flexibility and adaptability, Dependency
Injection, Strategy, and Observer patterns are effective. For user interface design, the
Model-View-Controller (MVC) pattern helps separate concerns and enhance
maintainability. Managing data access and storage can be efficiently handled using the
Repository Pattern. Integration with external services can be simplified with Adapter or
Facade patterns. Additionally, the Flyweight pattern is useful for optimizing memory usage
in performance-critical applications.

Additionally, it's important to consider developer familiarity, as using patterns the


development team knows well can result in more efficient and maintainable code. Each
pattern is most effective in specific contexts, so it's crucial to avoid over-engineering by
choosing patterns that meet actual needs. Lastly, select patterns that facilitate future
expansion, allowing for easy growth and changes without requiring major code overhauls.

For developing the sales data analysis application for Sampath Food City, choosing the
right data structures is essential for making the system efficient, easy to maintain, and able
to handle growth.

When we're building the sales analysis tool for Sampath Food City, it's super important to
pick the right ways to organize our data.

• Lists
• Dictionaries (Hash Maps)
• Queues
• Tree Structures

46 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
First off, when we talk about the stuff, we're keeping track of like sales, products, and
branches, we'll use lists. It's like making a list of all the things we've sold, all the products
we have, and all the branches we operate.

Now, when we want to quickly find something specific in our lists, we'll use something
called dictionaries, which are like special lists that let us find things super fast by using IDs.
So, if we want to find a branch or a product, we can do it really quickly with dictionaries.

In the part where we're storing all the sales records, we'll keep them together in one big list.
And to make it easy to find specific branches or products related to those sales, we'll use
dictionaries again. They'll help us quickly find details about branches or products based on
their IDs.

Now, when we're crunching the numbers to understand stuff like total sales for each branch
or product, or maybe we want to see how sales change over time, we'll use dictionaries to
store all that data. They're great for quickly organizing and looking up information. And if
we need to store some temporary results or individual sale amounts, we'll use lists.

Sometimes, we want to make sure we're not counting the same thing twice, like the same
product in different categories. For that, we'll use sets, which make sure we only count
unique things.

Lastly, when we're handling commands from the user, like what analysis to run, we'll use
queues to keep everything organized. It's like forming a line, so we process each request in
the order it came in, making sure things don't get mixed up.

If we need to analyse data that has a hierarchical structure, like sales by product categories,
we can use Tree Structures for the same.

By using these simple ways to organize our data, we'll be able to build a tool that's not only
easy to use but also efficient at understanding and analysing sales data for Sampath Food
City.

2.2 Design a suitable testing regime for the application, including


provision for automated testing.

To design a suitable testing regime for the sales data analysis application, we need to ensure
comprehensive coverage of all components and functionalities.

1. Unit Testing

Unit testing is like checking each small part of the code to make sure it works correctly on
its own. We write tests for each function or method to see if they do what they're supposed
to do. In Python, we have tools like pytest to help us do this.

For example, in our sales data analysis program, we would test each part that deals with
getting or changing data, making sure it does its job correctly. We'd also test the analysis
part to make sure it gives us the right results when we give it some sample data. This way,
we catch mistakes early and make sure everything works smoothly in the end.
47 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Examples:
• Test each method in the SaleRepository class to ensure correct data
retrieval and manipulation.
• Test analysis strategies to verify that they produce accurate results for
sample input data.

2. Integration Testing

Integration testing is about checking how different parts of the application work together.
We want to make sure that when we put all these pieces together, they still do what they're
supposed to do. We test them to see if they achieve specific tasks when they're working
together.

Just like unit testing, we use tools to help us do this efficiently. These tools are similar to
the ones we use for unit testing. By doing integration testing, we ensure that our application
runs smoothly as a whole, with all its different parts working together seamlessly.

Examples:
• Test the interaction between the CLI layer and the analysis layer to ensure
that user inputs are processed correctly.
• Test how the data repository interacts with the analysis layer to provide
data for analysis.

3. End-to-End Testing

End-to-end testing is like giving the entire application a real life run through, from
beginning to end. We want to see how everything works together just like it would for a
user. To do this, we automate interactions with the application, mimicking what a user
would do.

We perform a series of actions, like clicking buttons or entering data, and then check if the
results match what we expected. For web-based applications, we might use tools like
Selenium, while for command-line applications, we could create our own scripts. End-to-
end testing helps us catch any issues that might arise when all parts of the application are
put together, ensuring it behaves as expected for users in real world scenarios.

Examples:
• Automate user interactions with the CLI to simulate different analysis
requests and verify the correctness of the results.
• Simulate data ingestion and analysis processes to ensure that data flows
smoothly through the system.

4. Regression Testing

Regression testing is all about making sure that when we make changes to the code, we
don't accidentally introduce new problems or mess up things that were working fine before.
The idea is to re-run all the tests that passed before, after we've made changes, to make sure
everything still works as expected.

48 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
We use the same tools we use for unit testing and integration testing to do this. By regularly
running regression tests, we can catch any unexpected issues early on and keep our
application running smoothly.

Examples:
• After implementing a new feature or fixing a bug, re-run all existing test
cases to ensure that the changes did not introduce any regressions.
• Use version control systems like Git to track changes and run automated
tests in continuous integration (CI) pipelines.

5. Performance Testing

Performance testing is about checking how well our application performs and how much it
can handle when lots of people are using it at the same time. We want to know things like
how fast it responds to user actions, how much computer resources it uses, and how it
behaves when lots of users are using it.

To do this, we use tools called load testing tools, like Apache JMeter, or we can create our
own scripts. These tools help us simulate lots of users using the application at once, so we
can see how it handles the load. By doing performance testing, we make sure our
application can handle whatever users throw at it without slowing down or crashing.

Examples:
• Simulate a large number of concurrent users interacting with the
application to identify performance bottlenecks and optimize code and
infrastructure accordingly.
• Measure response times for different analysis requests to ensure that the
application remains responsive even with increasing data volume.

6. Usability Testing

Usability testing is all about checking how easy and enjoyable it is for users to use our
application. We want to know if the user interface is clear and if the overall experience is
good. To do this, we can ask real users for feedback or use special tools made for usability
testing.

These tools, like UserTesting or UserZoom, help us see how real users interact with our
application and where they might have trouble. Alternatively, we can simply ask users for
their thoughts and feedback directly. By doing usability testing, we make sure our
application is user-friendly and enjoyable to use, which is super important for keeping users
happy.

Examples:
• Conduct surveys or interviews with users to gather feedback on the CLI
interface and identify any difficulties or confusion.
• Iterate on the CLI design based on user feedback to make it more intuitive
and user-friendly.

49 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Automated Testing
Automated testing is about making our testing process faster and more efficient by letting
computers do the work for us. We want to automate tasks that we'd otherwise have to do
manually over and over again. This helps us test more things, more often, and get feedback
on our code faster. To do this, we write scripts or use special testing frameworks that can
run our tests automatically.

We can then integrate these tests into our development process using continuous integration
(CI) tools like Jenkins, Travis CI, or GitLab CI. These tools automatically run our tests
whenever we make changes to our code, giving us quick feedback on whether everything
still works as expected. By automating our testing, we can catch bugs earlier and ensure
our code is always in good shape.

Examples:
• Set up CI pipelines that automatically run unit tests, integration tests, and
end-to-end tests whenever code changes are pushed to the repository.
• Use test automation frameworks to automate repetitive tasks, such as data
setup for testing or simulating user interactions.

Test Data Management

The purpose of test data management is to make sure our tests use data that's reliable and
realistic. We want our tests to run with data that's consistent and looks like what the real
application would use. To do this, we can use mock data or special tools that generate test
data for us.

Mocking libraries like MagicMock for Python help us create fake data that resembles real
data. Alternatively, we can write our own scripts to generate test data that matches the
characteristics of the data our application would use. By using consistent and realistic test
data, we can ensure that our tests accurately reflect how our application would behave in
real-world scenarios.

Examples:
• Create mock sales data for unit tests to simulate different scenarios, such as
sales from multiple branches and products with varying prices and
quantities.
• Use test data generation tools to create large datasets for performance
testing, ensuring that tests are conducted with realistic data volumes.

50 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
2.3 Refine the Design and Include Multiple Design Patterns
Refining the design of the sales data analysis application for Sampath Food City and
incorporating multiple design patterns will enhance its structure, maintainability, and
scalability.

1. Repository Pattern
The Repository pattern is like having a dedicated manager for handling all the data stuff in
our application. It keeps the data-related tasks separate from the other parts of the
application.

So, instead of each part of the application managing its own data, we have this central
manager that takes care of storing and getting data for us. This makes it easier to keep track
of where the data is coming from and going to. Plus, it makes testing our application much
simpler because we only have one place to check for data-related issues.

Example: In our scenario, the SaleRepository class encapsulates methods for adding sales
records and querying sales data by branch or product.

2. Strategy Pattern
The Strategy pattern is like having different ways to solve a problem, and we can pick the
best one for the situation. Imagine we have different strategies for analyzing sales data: one
for monthly totals, one for product prices, and so on. Each strategy is like a different
approach to the same problem.

With the Strategy pattern, we encapsulate each strategy separately, making them easy to
swap in and out as needed. So, depending on what kind of analysis we want to do, we can
choose the right strategy at runtime. This flexibility allows us to adapt our analysis methods
without changing the main code.

Example: Different analysis strategies, such as MonthlySalesAnalysis and PriceAnalysis,


encapsulate algorithms for analyzing sales data in different ways. This allows us to switch
between strategies based on the analysis requirements.

3. Singleton Pattern
The Singleton pattern is like having a special rule that says there can only be one of
something. In our case, it's about having just one instance of a certain class in our whole
application. This can be really handy when we want to make sure that everyone in our
program is using the same version of something important, like a data repository.

By using the Singleton pattern, we ensure that no matter where in the program someone
asks for this thing, they always get the same one. It's like having a single point of contact
that everyone can rely on, making coordination between different parts of the program
easier.

Example: The SaleRepository class can be implemented as a singleton to ensure that there's
only one instance of the repository throughout the application, maintaining consistency in
data access.

51 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
4. Command Pattern
The Command pattern is like putting requests into neat little packages that we can handle
easily. Instead of directly doing something when a request comes in, we wrap that request
into an object. This object contains all the information needed to perform the request, like
what action to take and any data required.

By doing this, we can do lots of cool stuff with these requests, like putting them in queues
to be handled later, adding undo functionality to reverse actions, or logging them for
tracking purposes. It's like having a well-organized system for managing requests, making
it easier to handle and process them in different ways.

Example: The AnalysisCommand class encapsulates an analysis request, including the


analysis strategy and sales data. This allows us to queue analysis requests and execute
them at a later time.

5. Facade Pattern
The Facade pattern is like having a front desk at a big building. It provides a simple and
friendly interface for people coming in, hiding all the complex stuff that's going on behind
the scenes. In our software, it's similar.

We create a facade, which is like a front desk, that hides all the complicated details of a
subsystem. So, when other parts of the program want to use that subsystem, they don't have
to deal with all the complexity directly. They just talk to the facade, and it takes care of
everything for them. This makes it much easier to use the subsystem without worrying
about how it actually works internally.

Example: The SalesAnalyzerFacade class provides a simplified interface for analyzing


sales data. It hides the complexities of data retrieval and analysis strategies from the client
code, making it easier to perform analysis tasks.

52 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Activity 3

3.1 Build a large dataset processing application based on the design


produced.

To develop the sales data analysis system for Sampath Food City, the system can be broken
down into several key components. Each component will handle specific aspects of the
functionality required.

1. Sales Data Manager

Responsibilities
• Handle recording and storing of sales data for each branch.
• Provide methods to retrieve and analyze sales data on a monthly basis.
Data Structures
• sales_data: Dictionary of Lists

Figure 56 – Code example (Author created)

Methods
• record_sale(branch, date, total_sales, items_sold)
• get_monthly_sales(branch, month, year)

2. Price Data Manager

Responsibilities
• Handle recording and storing of price data for each product.
• Provide methods to analyze price trends.

Data Structures

Figure 57 – Code example (Author created)

53 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Methods
• record_price(product, price)
• get_price_trend(product)

3. Weekly Sales Analyzer

Responsibilities
• Analyze and store weekly sales data for the entire supermarket network.
• Provide methods to retrieve weekly sales data.

Data Structures
• weekly_sales: List of Dictionaries

Figure 58 – Code example (Author created)

Methods
• analyze_weekly_sales()
• get_weekly_sales(week_number)

4. Product Preference Analyzer

Responsibilities
• Track and analyze the popularity of each product based on sales data.
• Provide methods to retrieve product preference data.

Data Structures
• product_preference: Dictionary

Figure 59 – Code example (Author created)

Methods
• record_product_preference(items_sold)
• get_product_preference()

54 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
5. Sales Distribution Analyzer

Responsibilities
• Analyze the distribution of total sales amounts across all transactions.
• Provide methods to retrieve sales distribution data.

Data Structures
• sales_distribution: List of Tuples

Figure 60 – Code example (Author created)

Methods
• record_sale_distribution(branch, date, total_sales)
• get_sales_distribution()

6. Command-Line Interface (CLI)

Responsibilities
• Provide a user interface for interacting with the system.
• Allow users to input data and request analyses through command-line commands.

Methods
• display_menu()
• handle_user_input()

55 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Rough implementation outline incorporating all these components

56 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 61 – Rough implementation outline of the application (Author created)

57 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Main interface & Sample inputs

Figure 62 – Main interface of the application (Author created)

Figure 63 – Sample inputs 1 (Author created)

Figure 64 – Sample inputs 2 (Author created)

This design organizes the application into clear, manageable components, making the
system more maintainable and scalable. Each component has a defined responsibility and
interacts with others through well-defined interfaces. The command-line interface provides
a way for users to interact with the system and perform various analyses based on the
collected sales data.

58 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
To export data to different formats like TXT, CSV, ROW, and HTML, We can add methods
in our CLI class to handle the export functionality for each format.

Complete Python codes of the application

59 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
60 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
61 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 65 – Python code of the developed application (Author created)

62 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
3.2 Effectiveness of Development Principles and Patterns in our
Application Design

When dealing with large scale data processing, we follow certain principles and patterns to
ensure our code is high quality, justifiable, and scalable. These include principles like the
Liskov Substitution Principle (LSP), Interface Segregation Principle (ISP), Dependency
Inversion Principle (DIP), Open/Close Principle (OCP), and Single Responsibility
Principle (SRP), along with various design patterns.

SRP helps by breaking down our code into smaller, more understandable parts, each with
its own specific job. OCP allows us to easily add new processing methods without having
to change existing code. LSP encourages us to design our code so that different strategies
can be easily implemented and adapted. ISP helps us keep our code clean by tailoring
interfaces to meet specific needs, avoiding unnecessary complexity.

DIP makes testing and maintenance easier by reducing how much different parts of our
code rely on each other. Design patterns like the Builder pattern make it easier to create
and customize reports, while the Observer pattern allows for real-time adjustments during
data processing. The Strategy Pattern promotes code reuse and flexibility by letting us
easily switch between different processing methods.

By applying these principles and patterns together, we see significant benefits in terms of
better maintainability, flexibility, and scalability. Designing our code with a modular
approach in mind makes it simpler to make changes and updates in the future. Overall,
using SOLID principles and design patterns results in a cleaner, more effective codebase
for processing large data sets, which sets us up for success as our program grows and
evolves.

Comprehensive Assessment of SOLID Principles in Software Development

To make code easier to maintain and less prone to unexpected issues, the Single
Responsibility Principle (SRP) suggests that each class should have only one job. The
Open/Close Principle (OCP) helps maintain code stability by allowing us to add new
features without changing existing code. Liskov's Substitution Principle (LSP) ensures
smooth substitution and implementation of strategies by providing a consistent interface
for different data processing methods.

The Interface Segregation Principle (ISP) encourages a clean interface design and avoids
unnecessary dependencies by splitting interfaces into separate tasks. Dependency injection,
a realization of the Dependency Inversion Principle (DIP), allows higher-level modules to
depend on abstractions rather than specific implementations. This separation makes unit
testing with mock implementations easier and simplifies strategy replacement.

These principles have a significant impact on how software programs are designed and
function. They help ensure code is more modular, easier to maintain, and less likely to
cause unexpected problems.

63 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
The Impact of Clean Code Techniques on Software Development

We have already discussed about these previously. Applying clean code strategies is crucial
for enhancing readability, maintainability, and overall quality, especially in projects
dealing with large datasets. Principles such as DRY (Don't Repeat Yourself), concise
functions, robust error handling, thorough testing, efficient code, modularization,
consistent formatting, and clear naming significantly contribute to achieving these goals.

Breaking down the code into separate modules promotes maintainability, while clear
naming clarifies the purpose of each module. Consistent formatting, including proper
indentation and spacing, is maintained throughout the codebase. Thoughtful comments
provide additional context without cluttering the code. Using meaningful names instead of
hardcoded values improves code manageability and reduces errors, following the DRY
principle to minimize redundancy and isolate reusable elements.

To enhance readability and simplify testing, smaller, task-specific functions or methods are
preferred. Robust error-handling systems provide clear feedback and address potential
issues effectively. Comprehensive testing at multiple levels helps identify issues early,
improving program reliability. Adhering to clean code best practices significantly improves
understanding of the codebase, making it easier for developers to work with it.

Improved maintainability, supported by clean code practices, builds confidence in making


updates and modifications. These practices also promote effective collaboration among
team members, facilitating project cooperation. Ultimately, clean code practices reduce
technical debt and create a conducive development environment, essential for the long-term
success of projects dealing with large datasets.

Effectiveness of Programming Patterns in Software Development

To improve functionality, the program leverages specific design patterns. The strategy
pattern stands out for its ability to encapsulate algorithms and dynamically select them
based on client code requirements. This proves particularly useful for tasks like monthly
sales analysis and price analysis, where different strategies may be employed.

Although not explicitly implemented, the Singleton design pattern could be beneficial for
classes needing to maintain a single instance, such as Data Processing Context or Data
Reporting Context. By ensuring the existence of only one instance for each context class,
unnecessary instantiations are avoided, leading to more efficient resource utilization.

The Factory Method pattern offers enhanced flexibility by dynamically producing various
report types, which could facilitate future program development to accommodate additional
report types seamlessly.

The Observer design pattern is effective when system components need to respond to
changes, as often seen in logging or alerting systems. Integrating this pattern could be
valuable for notifications or logging during data processing, enabling system components
to react appropriately to alterations in data or system state.

64 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Activity 4

4.1 Different methods of implementing automatic testing as designed in


the test plan.

Automated testing means using tools and scripts to check if software works well. Instead
of people running tests and looking at results, computers do it automatically. This saves
time and effort, especially for tests that need to be done over and over again or take a lot of
resources.

Let's simplify each type of testing

Unit Testing

This check individual parts of the software, like functions or classes, to make sure they
work correctly on their own. For example, if we have a function that adds two numbers, we
test it to ensure it adds them up correctly. Tools like JUnit or pytest can run these tests
automatically.

Integration Testing

This tests how different parts of the software work together. For instance, if our program
has a front-end and a back-end, integration testing checks if they communicate properly.
Tools like Selenium or Postman can simulate user actions or API requests to automate these
tests.

Regression Testing

This makes sure that recent changes to the software haven't broken anything that was
working before. It automatically reruns test cases to catch any issues caused by new
updates. Tools like Selenium WebDriver or Apache JMeter can help with this.

Functional Testing

This checks if the software does what it's supposed to do based on its specifications. For
example, if we have a login page, functional testing verifies that users can log in
successfully. Tools like Cucumber or Robot Framework can run tests written in plain
language to automate this process.

Performance Testing

This tests how fast and stable the software is under different conditions, like heavy user
loads. Tools like Apache JMeter or Gatling simulate many users accessing the software at
once to measure its performance.

65 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Security Testing

This looks for security issues in the software, like vulnerabilities that hackers could exploit.
Automated tools like OWASP ZAP or Burp Suite scan the software for common security
problems automatically, such as injection attacks or cross-site scripting.

Continuous Integration/Continuous Deployment (CI/CD)

This automates the process of building, testing, and deploying software changes. Tools like
Jenkins or GitLab CI/CD can run automated tests whenever new code is added, ensuring
that the software remains stable and deployable.

Let’s discuss several automatic testing tools in python

PyUnit - It’s like a tool that comes with Python, and it helps us make and run tests. These
tests check if different parts of our code work well by themselves.

Nose2 - This is another tool for testing our code. It's nice because it can do many kinds of
tests, like checking if small parts of our code work, if different parts of our code work
together, and if our whole program works as expected. People like it because it's easy to
use and has many helpful features.

Doctest - Doctest is a simple way to test our code. We can write tests right inside the
explanations we put in our code. It's handy because we can make sure our code works
correctly while also making sure our explanations are right.

Robot Framework - This is a tool for testing our code in a special way. Instead of writing
tests in a hard-to-read format, we write them in a way that's easy for people to understand.
It's good for testing things like websites and making sure they work the way we want.

Behave - Behave is a tool for testing our code by writing down how we expect it to work.
It's like writing a story that describes what our code should do. This can help us make sure
our code does what we want it to do, from the perspective of someone using it.

Selenium - Selenium is like a helper for testing websites. It can pretend to be a person using
a web browser and check if a website works well. It's useful for making sure websites look
and act the way they're supposed to.

Splinter - Splinter is another helper for testing websites, but it's easier to use than Selenium.
It helps us do things on websites, like clicking buttons and filling out forms, so we can test
if they work correctly.

PyTest - PyTest is a tool for testing our code, and it's liked by many developers because
it's easy to understand and use. It helps us write different kinds of tests, like checking small
parts of our code, seeing if different parts work together, and making sure our program
works as expected.

66 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
4.2 Implement automatic testing of the developed application.

Choose a Testing Framework

This involves selecting a tool or framework that allows us to define and execute test cases
for our application. We can choose from popular options like PyTest, Nose2, or unittest,
depending on our project requirements and familiarity with the framework.

Write Test Cases


Test cases are specific scenarios or conditions that we want to validate in our application.
These cases should cover various aspects of our application's functionality, including both
normal and edge cases, to ensure comprehensive testing.

Organize Test Suites


Test suites are collections of test cases grouped together based on the functionality they
test. Organizing our test cases into logical suites helps in managing and executing tests
more efficiently, especially as our test suite grows larger.

Create Test Fixtures


Test fixtures are the preconditions or setups required for executing test cases. This may
involve initializing objects, setting up databases, or configuring the testing environment to
simulate real world conditions.

Write Test Functions


Test functions are the actual code that performs actions and assertions to verify the behavior
of our application. Each test function should focus on testing a specific aspect or feature of
our application.

Run Test Suites


Once we have defined our test cases and organized them into suites, we can execute the
test suites using the chosen testing framework. This typically involves running a command
or using an IDE plugin to initiate the test execution.

Analyze Test Results


After running the tests, analyze the results to identify any failures or errors. This involves
reviewing the test output or reports generated by the testing framework to pinpoint issues
that need to be addressed.

Automate Test Execution


To streamline the testing process, set up automated test execution as part of our CI/CD
pipeline. This ensures that tests are automatically run whenever changes are made to the
codebase, providing rapid feedback on the health of our application.

Monitor Test Coverage


Test coverage measures how much of our application's code is exercised by our test suite.
Monitor test coverage to ensure that our tests adequately cover all parts of our codebase,
helping to identify areas that require additional testing.

67 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Refactor and Maintain Tests
Regularly refactor and maintain our test suite to keep it aligned with changes in our
application. This includes updating test cases to reflect changes in functionality, improving
test coverage, and removing obsolete tests.

4.3 Differences between developer-produced and vendor-provided


automatic testing tools for applications and software systems.

Developer-produced automatic testing tools are those created and maintained by the
development team or organization responsible for building the software or application.
These tools are typically tailored to the specific needs and requirements of the project, and
they are often integrated seamlessly into the development process.

Vendor-provided automatic testing tools are developed and offered by third party vendors
who specialize in creating testing solutions for various software development projects.
These tools are commercially available and may offer a range of features and functionalities
to suit different types of applications and systems.

Differences between developer-produced and vendor-provided automatic testing tools

Customization

Tools made by developers are often tailored precisely to meet the needs and workflows of
the development team and the project. They're crafted to tackle the specific challenges and
requirements of the software being created. In contrast, tools provided by vendors are
typically more standardized and may not offer as much flexibility in terms of
customization.

Integration

Tools created by developers are usually smoothly integrated into the current development
setup and tools. They're designed to work closely with other tools like version control,
continuous integration servers, and issue tracking systems. On the other hand, vendor-
provided tools may need extra setup or integration work to fit well into the development
process.

Support and Maintenance

Tools made by developers need the development team to handle support and maintenance
tasks. This means the team manages updates, fixes bugs, and provides support, often with
limited resources available to team members only. On the contrary, vendor-provided tools
come with dedicated support and maintenance services offered by the vendor. This includes
regular updates, technical assistance, and access to documentation and training materials.

68 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Cost

Tools made by developers might be cheaper at the start because they're built internally,
meaning there are no fees for using them. But there could be ongoing costs for keeping
them up and running. On the other hand, tools from vendors usually come with fees for
licensing or subscriptions, but they might have more features and support options available.

Features and Functionality

Developer-made tools are created to fit exactly what the development team and project
need. They have features and functions that are customized to match the unique
requirements of the software being built. On the flip side, vendor-provided tools have a
wider range of features to attract more users, but they might not fit the project's needs as
closely.

4.4.1 Analyse the benefits and drawbacks of different forms of automatic


testing of applications and software systems.

1. Unit Testing

Benefits

Unit testing helps find bugs in small parts of the software. It makes sure each piece works
correctly on its own. For example, in our app, we can check if adding a sale works without
any mistakes.

Drawbacks

Writing these tests can take a lot of time, especially for complex software. Also, they might
not cover every possible situation, leaving some parts untested.

2. Integration Testing

Benefits

Integration testing checks if different parts of the software work together. It finds problems
when they connect. For example, in our app, we can see if adding a sale and updating prices
work together without any issues.

Drawbacks

Setting up these tests can be hard, especially for big systems. Also, they might need access
to other things like databases, which can be tricky.

69 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
3. Regression Testing

Benefits

Regression testing makes sure changes to the software don't break anything that was
working before. It helps keep the software stable over time. For example, in our app, we
can check if changing how we add sales doesn't break anything else in the system.

Drawbacks

Doing these tests can take a long time, especially for big systems. Also, they might need to
be done a lot, which takes up a lot of resources.

4. Functional Testing

Benefits

Functional testing checks if the software does what it's supposed to do. It makes sure it
works like it should from the user's point of view. For example, in our app, we can see if
users can add sales and view reports like they're supposed to.

Drawbacks

These tests might miss some things users could do, leaving some parts untested. They can
also be hard to automate for parts of the software with complex behavior.

5.Performance Testing

Benefits

Performance testing checks how well the software works under different conditions, like
when a lot of people use it at once. It helps us find problems with speed and stability early
on. For example, in our app, we can check if it slows down when many sales happen at
once.

Drawbacks

Doing these tests needs special tools and setup, which can be hard. Also, it's not easy to
make performance issues happen the same way every time we test.

6. Security Testing

Benefits

Security testing looks for ways bad actors could break into the software and steal or mess
with data. It helps keep sensitive information safe and stops attacks before they happen.
For example, in our app, we can check if people can't get into parts they're not supposed to
access.

70 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Drawbacks

Finding these security problems needs special knowledge and tools, which not everyone
has. Also, it can take a long time, especially for complex systems.

4.4.2 Employ Selected Testing Tools


Integration testing looks for problems that happen when different parts of the software work
together, while unit testing checks if each part works on its own. To make integration
testing easier, it's good to use continuous integration and build the software in small pieces.

Regression testing helps avoid repeating tests and saves time by focusing on important
areas. Performance testing tries to mimic how real users behave to see if the software can
handle it.

Using good practices in test automation, like running tests at the same time, and regularly
checking and changing the testing plan, helps save time and keep tests reliable. Cloud-
based testing lets us test in different setups and grow when needed. Checking the software
regularly helps find new problems and keeping an eye on it all the time makes sure it works
well.

Let’s employ Selected Testing Tools to Conduct Automatic Testing on our Developed
Application

Figure 66 – Pytest unit test code (Author created)

In this test file, we import the SalesDataManager class and create a fixture sales_manager
to instantiate the SalesDataManager object for each test case. We then define two test
functions: test_record_sale to test the record_sale method and test_get_monthly_sales
to test the get_monthly_sales method. Within each test function, we perform assertions to
verify that the methods behave as expected. Finally, we run the tests using pytest.

71 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
Figure 67 – Unit test code (Author created)

This code defines two test functions: test_record_sale and test_get_monthly_sales. Each
function tests a specific method of the SalesDataManager class by performing operations
and making assertions to ensure that the methods behave as expected. The pytest.fixture
decorator is used to create a fixture sales_manager that initializes a SalesDataManager
object for each test function. Finally, the tests can be run using pytest.

References

Used www.canva.com to create the cover page.

apollotechnical [online]Available at:https://www.apollotechnical.com/why-object-


oriented-programming-matters/ [Accessed 08.04.2024].

interviewbit [online]Available at:https://www.interviewbit.com/blog/characteristics-of-


object-oriented-programming/ [Accessed 08.04.2024].

profcdpatel [online]Available at:https://profcdpatel.blogspot.com/2020/01/basic-oop-


concepts.html [Accessed 10.04.2024].

devopsschool [online]Available at:https://www.devopsschool.com/blog/complete-


tutorials-of-php-oop-inheritance-with-example-code/ [Accessed 10.04.2024].

softwaretestinghelp [online]Available
at:https://www.softwaretestinghelp.com/polymorphism-in-java/ [Accessed 14.04.2024].

quora [online]Available at:https://www.quora.com/What-is-abstraction-4-pillars-of-


OOP-for-you-Can-you-give-a-brief-explanation-for-this-1[Accessed 24.04.2024].
72 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1
m2pfintech [online]Available at:https://m2pfintech.com/blog/solid-principles-a-
comprehensive-guide-to-object-oriented-programming-and-class-design-using-swift/
[Accessed 24.04.2024].

dabfreesm [online]Available at:https://dabfreesm.live/product_details/52998632.html


[Accessed 28.04.2024].

lifehackspro [online]Available at:https://lifehackspro.medium.com/top-9-design-patterns-


every-developer-should-know-about-c76df8d5643f
[Accessed 29.04.2024].

stackademic [online]Available at:https://blog.stackademic.com/creational-design-


patterns-b4090683c577?gi=29cb31319065 [Accessed 03.05.2024].

levelup [online]Available at:https://levelup.gitconnected.com/structural-design-patterns-


34c3daf9924b [Accessed 10.05.2024].

levelup [online]Available at:https://levelup.gitconnected.com/behavioural-design-


patterns-1a6a6bd390ee [Accessed 15.05.2024].

geeksforgeeks [online]Available at:https://www.geeksforgeeks.org/advantages-and-


disadvantages-of-automated-testing/ [Accessed 15.05.2024].

lambdatest [online]Available at:https://www.lambdatest.com/blog/types-of-automation-


testing/ [22.05.2024].

geeksforgeeks [online]Available at:https://www.geeksforgeeks.org/solid-principle-in-


programming-understand-with-real-life-examples/ [Accessed 25.05.2024].

geeksforgeeks [online]Available at:https://www.geeksforgeeks.org/design-patterns-cheat-


sheet-when-to-use-which-design-pattern/ [Accessed 25.05.2024].

momentslog [online]Available at:https://www.momentslog.com/development/design-


pattern/behavioral-vs-structural-vs-creational-design-patterns-when-to-use-each
[Accessed 26.05.2024].

73 | P a g e
T M Dayarathna Unit 20 - Applied Programming and Design Principles
Assignment no 1

You might also like