content
W1 -System Processes
SDLC
Plan
Code
Build
Test
Release
Waterfall
Plan
-> Software requirement documents, product roadmaps, what software should do...etc
Design -> Design architecture, user interface, database (Figma, ER models)
Code -> Developers working concurrently to work on different components in the software
Integration -> Combine all individual components to create a unified software
System Test -> Testing at the end of the software creation
✅ Logical and organised as the requirements are stated very early on; follows an iterative and incremental process. ❌ A plan is executed, and it is not purposeful; this method assumes plan is clear from the start, but an iterative and incremental process brings in uncertainty as there may be discovery of bugs, change in clients plan/goals midway through the project.
Agile Process
No standard template/checklists/procedures
More prescriptive than descriptive
Examples: Scrum, Extreme Programming (XP), Kanban

Scrum
Uses short iterations called sprints that focus on productivity
Breaks down a product into sprints, with each sprint focusing on one feature/task of the project.
After each iteration, show something to the client.
Roles:
Product Owner: Lead user of the system, person with the vision of what he/she wants to build
Team: Develops the product
Scrum Master: Facilitates the process of stand ups.
Process:
Plan
Customer presents user stories and prioritises the business value a feature will bring, and the developers will choose what features they can realistically deliver in a week
Execute
Review
Potentially, when done, customer tries the features in a working build.
XP
Focus on software engineering practices and quality
XP Main Practices
Pair Programming + Test-Drive Development (TDD)
Developers pair up to write automated tests like unit tests
Code is then written to make the test pass, and then refactored to improve code quality
Pairs rotate to share knowledge and improve code quality.
Continuous Integration
Automated build and test process for a team
Code Review and Refactoring
Studying of source code by others
Modify existing code to imrpove design, structure, without changing functionalities
Kickoff/Sprint Planning
Each project begins with a kickoff meeting
Overview of the project and the goals
Who will be working on the project
Determining the point person for client sign-off/contact
Creating project backlog
Determining which features to work on
Getting on the same page.
Software Operations
Operate
Make sure apps runs well, reliably and avail with adequate security
Monitoring
Be able to respond to any incidents early and predict future incidents
Handle Requests and Feedback from Users
Collect and analyse data on availability/performance, security and other operations-related processes.
Securtiy
Data Theft, Data tampering, DDoS
Internal and external threats
Access control: authorisation and authentication
Incidents and Recovery
Unplanned service interruption
Reduce quality of service
Minimize negative impact of incidents by restoring normal service operation as quickly as possible
To identify active and potential causes of incidents - prevent future incidents -proactive
Dev vs Ops
Dev became faster than ops because of agile
Testing and deployment were isolated activities done after code-build
Separate Dev and Ops team timelines did not align well
DevOps team
About collaborating to quickly develop deploy and support production
CICD
CI: Automating software build and test
CD: Pipeline to build, test and deploy the whole package.
Dev Ops Anti-Pattern
Assign role of DevOps Engineer ⇒ No point! We are trying to collaborate so that everyone is doing Agile
DevSecOps
Traditionally, security if an afterthought, and dev team might be disbanded by the time security testing are run and software issues are found.
Security team finds it hard to understand root causes of software issues.
Automate core security by embedding security practices and considerations in SDLC.
To start:
Plan on where, how and where security testing will be done: Jira, Slack, IriusRisk
SAST/DAST, code analysis, code reviews: Gerrit, PMD, SpotBugs, Copilot
Build: OWASP Dependency-Check, Synk, SonarQube
Test: ZAP, BurpSuite
Release: Ansible, Chef, Docker
Deploy: Osquery,Chaos Monkey
Operate: IMperva RASP, Alert Logic
W2
Software Requirement
Customers must communicate with the software-building team
This is a business vs technical side kinda situation
If either side dominates the communication, the project loses
All about functionalities and time, little to no concern on whether the tech team understand what is needed, or able to deliver by deadlines.
Hard to predict software projects
Requirements, Complexity grows and changes as the project progresses
Difficulty to estimate how long thinfs will take
User story
Define things user want from your product
"As a (XX user), I want to [do smth] so that i can [get to the goal]"
Product Backlog
Something that is continuously derived and refined from large/existing customer stories.
Usually describes the features, known issues/defects/research that is related to the product.
Backlog is something continuously refined
Product Backlog Operations Requirements
Consider: availability/latency/operational performance -> how much downtime?, scaling, monitoring needs
Logging: what to log, purposes, and how to proper logging
Testing needs: dynamic security testing, penetration testing
Security and compliance: SAST, encyrption, data protection
User Story: Components:
1) Card - holds the story
2) Conversation - Detailed requirement (what models, what classes, what teams)
3) Confirmation - Acceptance criteria
INVEST
Independent
Negotiable - flexible implementation choices
Valuable
Estimable
Small
Testable
Production:
User Testing/Accepting
Business and Technical Stories are the same, stories
Business stories are dependent.
Story to Epic -> 1 to 1
Technical Story to Epic -> M:1
W3
Snapshots vs Delta-based (Difference) Version Control
W3
Component
A class file/jar file, etc.
Service
Uses protocols
An application outside of core application that communicates with the main application
DI can be done on Componenets and Services.
Coupling
A situation in which a class depends on another concrete class
Tight coupling: Hard to change/modify
Dependency Injection
A system design pattern that connects components into apps
Need for this might not be clear.
if we allows class to create dependences, the parents need to change
Tight coupling
Loosely dependent code
Car is not responsible to creating driver type.
Do your own thing kinda concept
DI implements IOC concept
>> Makes more things modularised, by injecting anything a concrete class needs; rather than making the class create what it needs.
This makes the injected dependency open for extension
✅ Easier to unit test
✅ Java Standard under JSR 330
❌ Difficult to read and debug code
❌ Dependence on DI frameworks
Circular Dependency
Chicken or Egg thing
The solution is to use a setter injection to bypass the circular dependency
Spring Bean lifecycle
Set application context, preDestroy, Destroyed
Spring will manage this for you
Spring Framework
Component-based software
Create/Manage beans
SpringBoot
Helps to abstract from boiler codes
Less monolithic, more microservices
More abstraction, more devops
AutoConfiguration/Classpath
Monolithic
❌ Hard to scale everything is bloated
Microservices
to FrontEnd too
Micro front-end ->
Loose coupling
REST/SOAP
Uses multiprotocols
Streamable HTTP
HTTP Methods
Safe -> Will not change the resource
Idempotent -> Can be called several times with the same results
POST
N
N
GET
Y
Y
PUT
N
N
DELETE
N
N
Best Practices
Use correct verbs for actions
Use only logical nesting for paths
Return appropriate error codes
Version your API, and show major only
MAJOR.MINOR.PATCH
Major ⇒ Breaking Changes
Minor ⇒ (99% updates here - does not affect consumers, backend kinda of stuff)
PATCH ⇒ Bug Fixes (Changelog - Major Version)
In Spring:
@Get/Post Mapping
@ResponseStatus
@RestController
GraphQL
Can specify field, more personalised
Order ala carte
W10
Software Verification
Purpose: Uncover problems in program, which increases the confidence in the code’s correctness
Techniques:
Formal Verification
Construct a formal proof that program is correct
Code Review
Other programmers to read your code
Testing
Only discovery of bugs
Purpose:
Reveal most important feature of the program
Clarifies software specifications - shows inconsistency in either specs/program
Learn about how the program behave under various conditions
Verifies contracts
Find software failures before they can occur
How?
Run programs on selected inputs and check the results
Challenges
Exhaustive testing is not efficient – too many test cases
Haphazard testing – less likely to find bugs
Random/Statistical testing – does not work well for software
There are issues that are unique to software testing:
Software behaviour being unpredictable – works fine for a range of inputs, then fail at boundary point
No prior evidence that software is going to fail
Test cases must be chosen carefully and systematically
Testing Attitude: Try to make it fail – be as brutal as possible
Debugging (DIfferent from Testing!)
- Discover and fix faults(bugs)
- Fixing/Debugging can take even more time than the original implementation
- Key to debugging is to find the simplest input that triggers the bug
Test-Driven Development
Good to test early and frequently
Practices:
Write tests even before code
Implement a new Java method
Write specification for the method
Write tests that exercise the spec
Write actual code, till code passes all tests
Specifications include:
Method signature (ie. name of function + parameters)
Input/Output
Constraints and descriptions
⭐ Fix spec issues first before wasting time coding
⭐Test-first gives more confidence in your code
Blackbox vs Whitebox Testing
No visibility into the internal code
Choose test cases with knowledge of code internals
Look at the specification – behaviors that are visible to clients
Systematically test different elements in the code
Domain coverage – test different parts of the input domain
Code coverage
Input Space Partitioning
Realistically, we can’t test all inputs
Divide the input space into equivalent partitions
Ensure that at least one test case covering a partition
Aims to ensure broad coverage
To find partitions:
Work out cases in the specification
Set of invalid inputs
Think of a range of numbers
Error Messages
⭐ Avoid writing similar test cases
Boundary Value Analysis (One of the potential partitions)
Aims to focus on detecting defects that are more likely to occur at extreme ends
Boundary values are extreme/unique cases at/around “boundaries” of partitions
Ie. Null references, first/last elements of a list, zero-length inputs, max-length input
Importance: bugs often occur at boundary values due to off by one mistakes
Code Coverage
Checks how thoroughly a program is exercised via test
Types of coverage:
Statement coverage
Portion of program statements touched by some test cases
100% statement coverage is common
Branch coverage
Portion of conditional branches are covered by test cases
Stronger than statement coverage, as 100% branch coverages automatically achieves/guarantees 100% statement coverage
Path coverage
Portion of all possible paths covered by test coverage
Not possible to achieve 100% coverage if there is a loop
Stronger than branch coverage, if 100%, then the guarantees, branch and statement coverage
⭐ Can use tools such as JaCoCo to compute coverage automatically for Java
How to achieve coverage?
Assertion-Free Testing
o ❌Tests cover code but never fail due to lack of assertions, thus meaningless
- Limitations of Code Coverage
o Too much focus on coverage may miss important bugs
o Coverage is not a good criterion to determine if program is sufficiently testing, use coverage to find places where testing is inadequate
Testing Practices – unit testing
- Unit Testing is whitebox tests written by coders, and to verify small units (methods/classes of program)
- Testing functions in isolation makes it easier to debug – able to localize errors
- Tool: Junit through @Test
o @Test
o Assertions contain functions to check results
§ Ie. assertEquals(expected results, function results)
o Should be Automatic, Repeatable and Independent
- AAA Pattern
o Arrange
§ Code required to setup a test – create new object/mock setup
o Act
§ Calling/Invocation of the Method being tested
o Assert
§ Check if expectations are met
o Must avoid multiple AAA sections in a unit test, and if statements
- Other Annotations
o @BeforeAll/@BeforeEach
§ Used to set up whatever conditions are needed for tests
§ @BeforeAll – runs once
§ @BeforeEach – run before every test
o @AfterEach
§ Tear down code, resets the test environment after each test
- Naming Tests
o Test name should express intent of test
o Typical Naming convention: Name + Scenario + Expected Behaviour
o Not compulsory, but suggested
- Mocking
o The need to model other components in unit testing
o Create mock objects to simulate the real behaviours through minimal representations of APIs for these components, and allow for fast execution of test cases
o Can be done using Mockito
§ @ExtendWith(MockitoExtension.class)
· Load Junit extension to enable Mockito in the test class
§ @Mock
· Create a mock implementation of an annotated variable in the test class
§ @InjectMocks
· Create an instance of the class, and inject implemented mocks into annotated variables
o Stubbing
§ A Function call on a mock object
§ Defines what to do when specific methods of the mock are called, else the mock will return default values (0, null, false)
o Verifying
§ If mock has been used, verify that interactions happens
§ Can verify if method is called how many times
· verify(book, times(1)).save(book)
- Testing Practice: Integration Test
o Test a combination of components/entire program
o Mainly testing interactions between components
o Good practices:
§ Do not go directly from unit tests to whole program tests
· Hard to identify which component causes each issue
o Integration tests can be destructive – ie. Change backing data
- Testing Practice: Behaviour Driven Development
o Use Gherkin language to specify tests which are derived from the acceptance criteria
§ “Given” (context) , “When” (event occurs), “Then” (ensure come outcome)
§ ✅Simple, Easy to Read/Write
- Integration Tests with Spring Boot and REST
o @SpringBootTest annotation
§ Creates full Spring app context
§ Can test without actual HTTP server using Spring MockMvc
§ Injection of the port: @LocalServerPort
o Using Rest Assured
§ A Java library designed to simplify testing REST APIs
§ Provide BDD keywords – given().header().contentType().body(); when(); then()
- Testing Practices: Regression and Acceptance Tests
o Goals: Check to ensure fixed bugs stay fixed because new bug fixes often introduce new issues/bug
o Regression Testing
§ Run previously passed tests every time the application changes
o Acceptance Testing
§ For customers to evaluate the system’s compliance with the requirements
Last updated