Software Architecture: Model Validation, Design Patterns, Singleton, and Anti-Patterns
Software Model Validation and Software Quality
Assignment Specification Update:
- A bug was discovered in the assignment specifications, and an updated version was uploaded at approximately yesterday.
- Any assignment specification downloaded prior to yesterday must be replaced with the updated version containing fixes.
Software Model Validation using AI Tools:
- System requirements can be tested in AI tools such as Copilot to generate PlantUML syntax.
- Pasting AI-generated PlantUML syntax into the PlantUML web tool renders complete Unified Modeling Language (UML) software diagrams.
- PlantUML visual notation key:
- Green dots represent public methods.
- Red squares represent private methods.
- UML features captured include class hierarchies, abstract classes, associations, attributes, access levels, and methods.
- Comparative Analysis of AI Modeling:
- An evaluation conducted a year or two prior by testing ChatGPT (via Judy) yielded a UML diagram that differed significantly from Copilot's output.
- ChatGPT output evaluation: Exhibited poor design quality, completely lacking class inheritance and relying heavily on bidirectional associations.
- Copilot output evaluation: Rendered class hierarchies with abstract classes and explicit associations, though it presented potential overengineering.
- Strategic Use of AI in Software Engineering:
- AI should be treated as a collaborative brainstorming teammate to validate UML diagrams against initial requirements.
- Evaluation checklist for AI models: Verify whether the design is semantically correct, structurally consistent, well-designed, and capable of supporting all system use cases and requirements.
Software Quality and Clean Code Attributes:
- Core clean code attributes reviewed from Week 3:
- Structure
- Naming conventions
- Comments
- Documentation
- Fundamental software quality attributes ensuring long-term architectural stability across changing environments:
- Maintainability: Ease with which software can be modified or corrected.
- Clarity: Direct readability and comprehensibility of the codebase.
- Testability: Facility with which the software can be verified through tests.
- Portability: Ability of the software to operate across diverse environments.
- Transition from Models to Implementation Code:
- Class diagrams specify class hierarchies, inheritance, attributes, access modifiers, and method signatures.
- State diagrams define the operational behavior and state transitions within method bodies.
Foundations of Software Design Patterns
Code Reuse vs. Design Pattern Reuse:
- Code Reuse: Importing external libraries backed by active open-source communities to save development time while maintaining confidence in code quality and testing.
- Design Pattern Reuse: Reusing high-level structural, class, or behavioral concepts and architectural strategies rather than duplicating verbatim lines of code.
- Structural Components of a Pattern:
- Context
- Problem
- Solution
Analogies for Pattern Recognition:
- Rubik's Cube: Recognizing a specific physical state of the cube and executing a pre-determined sequence of rotations/moves to transition it into the target solved state.
- Chess: Recognizing board states to execute proven tactical move sequences, positional strategies, and specialized opening patterns.
Historical Context and Definitions:
- Christopher Alexander Definition: A construction designer who posited that a pattern describes a recurring problem in the environment along with the core solution, enabling the solution to be executed a million times over without doing it the exact same way twice.
- The Gang of Four (GoF) Publication ():
- In , four authors published the seminal book Design Patterns.
- Documented foundational design patterns centered around Object-Oriented Programming (OOP) using C++ concept examples.
The Four Essential Elements of a Design Pattern:
- Name: A single concise descriptor used to reference and communicate the design concept.
- Problem: Describes the context and specific conditions that must be present for the pattern to be applicable.
- Solution: An abstract structural template applied to resolve the underlying software problem.
- Consequences: The complete set of results, benefits, and trade-offs of applying the pattern (primarily positive, though negative consequences must be weighed).
- Note: The original GoF book breaks pattern analyses down into detailed sections.
Categorization Matrix of Design Patterns:
- The patterns are organized into primary categories across scopes (Class-level and Object-level):
- Creational Patterns: Focus on object instantiation mechanisms, providing ways to create objects while hiding creation logic instead of directly invoking constructors (e.g., avoiding explicit
book = new Book()calls) to enhance flexibility. - Structural Patterns: Focus on class and object composition, utilizing inheritance and interfaces to organize structure.
- Behavioral Patterns: Focus on interaction and communication protocols between objects.
Implementation Workflow for Design Patterns:
- Understand the pattern thoroughly, including its context, applicability, and broader architectural consequences.
- Review reference code and online documentation (such as the Gang of Four pattern resources provided on Moodle).
- Analyze UML structural descriptions to recognize interaction arrangements.
- Define classes and inheritance hierarchies, accounting for pre-existing system classes that will be impacted.
The Singleton Design Pattern
Classification and Architectural Intent:
- Pattern Classification: Object-level Creational Design Pattern.
- Primary Intent: Ensure a class has exactly one instance while providing a global point of access to that instance.
Applicability Criteria:
- Must be applied when exactly one instance of a class is required, accessible to all clients from a single well-known access point.
- Must be applied when the single instance needs to be extensible via subclassing, enabling clients to utilize an extended instance without altering client code.
Step-by-Step Practical Implementation Mechanics:
- Declare the default constructor as
privateto prevent external objects from using thenewoperator on the class. - Declare a
private staticfield within the class to store the single cached instance. - Implement a
public staticcreation method (e.g.,getInstance()) that invokes the private constructor internally on first execution and returns the cached static instance on all subsequent calls.
- Declare the default constructor as
Comparison of Initialization Strategies:
- Lazy Initialization:
- The static instance variable is initialized to
nullby default. - The
getInstance()method checks if the instance variable isnull; ifnull, it executes the private constructor and assigns the object before returning it. - Advantage: Conserves memory by deferring object instantiation until the instance is explicitly required.
- Disadvantage: Requires an explicit conditional
null-check on every execution ofgetInstance(). - Eager Initialization:
- The static instance is initialized immediately upon class loading (e.g.,
private static Singleton instance = new Singleton();). - The
getInstance()method directly returns the pre-instantiated static field without conditional checks. - Advantage: Saves computational overhead by eliminating the runtime
null-check step per access call. - Disadvantage: Allocates system memory immediately upon class loading regardless of whether the instance is ever consumed.
UML Structural Key:
- Identified by a self-referential association loop pointing back to the class itself.
- Attributes:
- instance: Singleton(private static field). - Constructors:
- Singleton()(private constructor). - Methods:
+ getInstance(): Singleton(public static getter).
Practical Case Studies:
- Android Tap-Target Game:
- Application requires tracking user taps on a moving target over a fixed duration.
- System components
Activity1_StartandActivity2_Playboth require access to the score tracker classCountTracker. - If two separate instances of
CountTrackerexist, theircountValueattributes diverge, breaking the score display. MakingCountTrackera Singleton guarantees both activities reference the exact same state. - Assignment 2 Architecture (
GameStateClass): - Class diagram contains
private currentGame(orGameState), a private constructorGameState(), and apublic static getInstance()method. - This structure confirms that
GameStatemust implement the Singleton design pattern. Either lazy or eager initialization may be chosen.
Technical Criticisms and Limitations:
- Violates pure Object-Oriented Design (OOD) standards by restricting standard instantiation and hiding constructors.
- Introduces multi-threading race condition vulnerabilities (thread safety risks) if synchronization is omitted.
- Subject to encapsulation failure via Java Reflection APIs, which can force access to private constructors and break uniqueness guarantees.
- Introduces global state into application architecture, creating tight coupling and hidden dependencies.
Software Anti-Patterns
Definition and Overview:
- Anti-patterns are common software development practices or design strategies that initially appear beneficial but ultimately yield negative consequences that far outweigh any short-term gains.
The Blob (or God Object):
- Description: A class or package that takes on excessive responsibilities and accumulates unstructured logic.
- Prevention Rule: If a class's functionality cannot be fully described in a single concise sentence, it possesses too much responsibility and must be refactored into multiple distinct classes.
The Childless Blob:
- Description: A class that relies on extensive conditional branching (
if/elseorswitchlogic) checking role/type attributes to govern behavior, rather than using object-oriented polymorphism and inheritance. - Structural Example: A
Personclass containing aroleattribute ("author","customer","librarian") where operations likeloanBook()execute conditional branches checkingif (role == customer). - Negative Consequences: Results in unmaintainable, fragile code. Adding a new role requires updating conditional statements across all methods in the codebase.
- Description: A class that relies on extensive conditional branching (
The Golden Hammer:
- Description: The practice of universally applying a single familiar technology, programming language, design pattern, or framework to every software problem regardless of suitability (fitting every shape into a square hole).
- Example: Indiscriminately applying JavaScript across web frontends, backend servers, Android apps, and iOS apps.
- Prevention Strategy: Practice continuous professional upskilling and objectively analyze specific domain problems to choose the best tool for the job, setting personal developer preferences aside.
- Counter Anti-Pattern Warning: Over-adopting bleeding-edge, unproven, or experimental technologies/libraries to stay on the absolute latest trend. This leads to code instability, reduced readability, and maintenance strain across software teams.