Please enable JavaScript.
Coggle requires JavaScript to display documents.
Software Design Principles, Pattern: A reusable solution to a recurring…
-
Pattern: A reusable solution to a recurring problem in a specific context.
Patterns are characterized by their repetitiveness, order, predictability, and regularity, making them essential tools for designing efficient and reusable solutions.
Influence of Building Architecture on Software Architecture
- Both share principles of structure, design, and utility.
- Patterns in architecture provide proven solutions for recurring problems.
MVC Pattern: Divides software into three interconnected components: Model (data), View (UI), and Controller (logic).
Architecture Patterns:
- Composed of components, relationships, and views.
- Provide repeatable solutions for specific behaviors or functionalities.
Influence of Building Architecture on Software Architecture
- Both share principles of structure, design, and utility.
- Patterns in architecture provide proven solutions for recurring problems
-
Views of Architecture:
- State View: Tracks changes in objects or data.
- Communication View: Examines interactions among components, such as the model, view, and controller in MVC.
Four Views of Architecture:
- Conceptual Architecture: Focuses on components and connectors.
- Module Architecture: Organizes the system into subsystems and modules.
- Code Architecture: Specifies file organization, libraries, and directory structure
- Execution Architecture: Defines tasks, threads, and processes for operational functionality.
Understanding Patterns
Attributes of Patterns:
- Repetition, Order, Predictability, and Regularity.
- Patterns simplify complex designs and provide reusable templates.
Characteristics of Patterns:
- Built from elements like shapes, sizes, and colors.
- Applied in software for robust, reusable solutions.
Value of Patterns:
- Accelerate design by leveraging existing experiences.
- Patterns evolve with use, refining over time.
Limitations of Patterns
- Patterns are starting points but not complete solutions.
- Specific solutions require customization beyond patterns.
-
-
Creational Patterns:
- Abstract object instantiation to make systems independent of object creation.
- Focus pattern: Singleton, which ensures a class has only one instance.
Creational Pattern: Singleton
- Definition / Intent: Ensures a class has a single instance and provides global access to it.
- Motivation: Prevent issues caused by multiple instances of critical classes (e.g., Printer Spooler, Window Manager).
- Applicability: Use when one instance of a class must coordinate actions across a system.
Structural Patterns:
- Deal with the composition of classes/objects into larger structures.
- Focus pattern: Decorator, which dynamically adds responsibilities to objects.
Structural Pattern: Decorator
- Definition / Intent: Dynamically adds responsibilities to objects without affecting others, providing a flexible alternative to subclassing.
- Motivation: Enhance functionality of specific objects (e.g., adding scrollbars to a text editor).
- Applicability: Use for dynamic and independent modification of object behavior
-
Behavioral Pattern: State
- Definition / Intent: Allows an object to change its behavior when its state changes.
- Motivation: Enable objects to respond differently depending on their internal state.
- Applicability: Use when objects must modify their behavior dynamically based on their state (e.g., TCP connection states or UI elements).
State Pattern:
- Links object behavior to its state.
- Simplifies complex conditional logic based on state.
Object-Oriented Design (OOD):
OOD is a software design approach where the solution is organized around objects and their interactions.
**Key Purpose**: Promote modularity, reusability, and maintainability.
Bottom-Up Design: Once problem-solving is complete, components are designed and assembled as building blocks in a modular fashion.
Modeling Tools: UML, class diagrams, and use-case diagrams assist in visualizing object relationships and system control flow.
Design vs. Programming: OOD is about planning and structuring the system, while OOP is about implementing that design.
-
-
Contain and Delegate: A design principle to avoid deep dependencies by delegating responsibilities to smaller classes, making code more modular and reusable.
Refactoring: The process of restructuring existing code without changing its behavior to improve readability, maintainability, and efficiency.
- Refactoring, which is restructuring code without altering its behavior, enhances readability and maintainability but requires conscious planning, particularly when dealing with complex systems
- Refactoring is not the same as debugging or removing syntax errors; it involves structural changes to make code easier to understand and modify.
- The "rule of three" is suggested: write code once, repeat if necessary, and refactor after the third instance.
- By dividing tasks into "two hats" & wearing one at a time (refactoring and functionality addition), developers can address code quality issues methodically.
Refactoring of Methods:
- Extract Method: A refactoring technique where a section of code is moved into a new, separate method, improving readability and reusability.
- Inline Method: A refactoring technique where the code of a private method is directly placed in the calling method, removing the method call.
- Move Method: Relocating a method to the class where it logically belongs, enhancing cohesion and reducing dependency.
Refactoring of Objects
- Responsibility Distribution: Move methods and fields to appropriate classes to ensure each class has a clear responsibility
- Extract/Merge Classes: Separate or combine classes to avoid bloat or redundancy.
- Encapsulation: Hide unnecessary class dependencies using inline classes or encapsulation techniques.:
Refactoring of Data:
- Self-Encapsulation: Use getters/setters for accessing data fields to maintain data integrity.
- Encapsulate Primitive Data: Replace primitive types with objects to represent data roles better.
- Replace Magic Numbers: Use symbolic constants to avoid hard-coded values that may lead to errors.
Refactoring of Conditionals:
- Simplify Conditionals: Break down complex conditionals and consolidate similar conditions for readability.
- Replace Switch Statements: Use polymorphism in object-oriented programming instead of switch cases.
- Guard Clauses: Use guard clauses for special cases instead of nested conditionals.
Refactoring of Method Calls:
- Meaningful Naming: Ensure method names reflect their function.
- Combine or Simplify Parameters: Consolidate parameters into objects when there are too many.
- Separate Queries from Modifiers: Avoid modifying the state within methods intended to query information.
Refactoring of Hierarchies:
- Pull Up/Push Down Refactoring: Moves methods or fields either up (to a superclass) or down (to a subclass) to generalize or specialize functionality.
- Constructor Handling: Constructors can be moved within the hierarchy using a factory method to encapsulate instantiation logic.
- Form Template Method: This is used when multiple methods have similar structures but different details, facilitating code reuse and standardization.
Overhauling/Big Refactorings: big refactorings are not redesign, but still they will require both design thinking and refactoring of ideas and implementation both.-
These are larger-scale refactorings that impact the entire project and involve the whole team. Big refactorings aim to align implementation with design principles and may require rethinking previous changes. Key techniques include:
- Tease Apart Inheritance: Untangles complex inheritance hierarchies by simplifying relationships between classes.
- Convert Procedural to Object-Oriented Design: Restructures procedural code into an object-oriented format to improve modularity and readability.
- Separate Domain from Presentation: Isolates business logic from the user interface, which can make the code more modular and adaptable.
- Extract Hierarchy: Refactors large, complex classes by dividing them into smaller, more manageable subclasses.
Design for Reuse: Creating software components that can be repurposed in different contexts to reduce development time and costs.
Architecture
The Mud to Structure series introduces architectural patterns that transform unstructured, chaotic systems into well-organized structures to achieve portability, maintainability, and understandability. This concept applies primarily to software design but draws inspiration from broader engineering principles.
Layers:
Layers Pattern: Hierarchical, modular, used in networking (e.g., OSI).
- Context: Large systems requiring decomposition.
- Problem: Need for communication across levels.
- Solution: Decompose systems into manageable layers.
Pipes and Filters:
Pipes and Filters: Sequential processing, modular, ideal for IoT and data pipelines.
- Context: Data streams needing sequential processing.
- Problem: Ensuring modular and flexible processing.
- Solution: Use filters for individual tasks connected by pipes.
Key Patterns in the Mud to Structure Category:engineering principles.
- Layers: Organizes systems into a hierarchy of tasks or abstractions. Communication flows between these layers, often horizontally arranged. Commonly seen in networking (e.g., OSI model).
- Pipes and Filters: Structures systems to process data streams through sequential filters connected by pipes. Each filter performs a specific function, allowing flexibility and modularity.
- Blackboard: Suited for problems without deterministic solutions, this pattern supports systems in immature domains by iteratively generating and testing solutions.
Blackboard:
Blackboard Pattern: Iterative solution exploration, useful for AI and emerging domains.
- Context: Immature domains with undefined solutions.
- Problem: Generate solutions iteratively with evolving knowledge.
- Solution: Use cooperative independent programs to explore possible paths.
Overview of Distributed Systems
Distributed systems consist of interconnected nodes with independent functionalities, working together to achieve scalability and high performance. Examples include cloud platforms, IoT systems, and modern web applications.
Architectural Patterns in Distributed Systems
- Pipes and Filters: A pattern primarily used for processing streams of data. In distributed systems, nodes perform specific processing tasks, with connections (pipes) facilitating communication.
- Microkernel: Used in adaptable systems to provide standardized services while adapting to different hardware environments.
- Broker Pattern: The primary focus of this video series, this pattern decouples components, allowing them to interact efficiently through a broker for remote invocation.
Detailed Study of the Broker Pattern
- Role: Coordinates communication between requesting and responding nodes, handling requests, results, and exceptions.
- Applications: Examples include city information systems, IoT-based factory monitoring, and educational admissions portals.
- Components: Includes clients, brokers, servers, and proxies (client-side and server-side) to enhance performance and scalability.
Interactive systems are a category of architectural systems where user interaction is key, often through graphical user interfaces (GUIs) and multi-modal inputs (keyboard, mouse, touch, camera, etc.). These systems emphasize the separation of concerns between the UI and the functional core to allow independent and flexible update
Key Patterns in Interactive Systems
Model-View-Controller (MVC):
- Divides the system into:
- Model: Manages core functionality and data.
- View: Displays the information to the user.
- Controller: Handles user inputs.
- Enables independent updates to UI and functionality while working cooperatively.
- Frequently used in modern web and mobile applications, allowing flexibility in changing views or enhancing UI elements.
Presentation-Abstraction-Control (PAC):
- Organized hierarchically with cooperating agents.
- Each agent has a specific responsibility (e.g., managing data, presenting UI).
- Provides flexibility for upgrades and is ideal for distributed and hierarchical system designs.
- Suitable for hierarchical systems like IoT applications, where different agents manage raw data, metadata, and reporting.
PAC Hierarchy:
- Agents: Responsible for specific tasks, communicating in a hierarchical structure.
- Flexibility: Each layer can be upgraded independently.
Introduction to MVC
Purpose:
- MVC is an architectural pattern for interactive systems, especially GUI-based applications.
- It provides a framework to separate UI from the functional core.
- Allows for scalable and maintainable software.
Why MVC?
- UI changes are frequent and often independent of the core functionality.
- Multilingual and configuration-based UI flows are common.
- Separating the UI and functional core simplifies maintenance and updates.
Core Concepts of MVC
- Components of MVC:
- Model: Handles data and business logic.
- View: Displays data to the user.
- Controller: Mediates user input and updates between Model and View.
- Interaction Flow:
- User input is captured by the View.
- The Controller processes the input and interacts with the Model
- The Model updates data and notifies Views of any changes.
- Views refresh to reflect the updated data.
Features and Benefits
- Facilitates decoupling: Changes in one component (e.g., UI) do not affect others.
- Supports dynamic views: Multiple ways of displaying data (e.g., charts, tables).
- Implements change propagation: Ensures all components are synchronized.
Implementation Details
- Design Steps:
- Separate human-computer interaction (UI) from core functionality.
- Establish a mechanism to propagate changes from Model to View.
- Design and implement the relationships between View and Controller.
- Build dynamic views and enhance the system with pluggable components.
- Implement the set up of MVC.
- Observer Pattern:
- Ensures all components (Model, View, Controller) are updated.
- Uses an
update() method to notify changes.
Workflow:
- User interacts with View → Controller processes input → Updates Model → Model notifies View.
-
Adaptable Systems:
Definition and Need for Adaptable Systems:
- Systems evolve to accommodate changes in technology, user interfaces (UI), and hardware.
- Adaptable systems are designed to absorb and implement changes efficiently.
Architectural Patterns:
- Microkernel: Enables systems to adapt to changes by separating core functionality from extended features.
- Reflection: Allows systems to dynamically adapt behavior and structure by being self-aware via meta and base levels.
Microkernel Pattern:
- Purpose: Separate core functions from extended/customizable parts to ensure adaptability.
- Structure:
- Core: Implements essential services like communication and resource handling.
- Servers & Adapters: Handle external and internal requests and interactions.
- Applications: Used in OS design (e.g., Android, iOS) for enabling multiple apps with a shared functional core.
Reflection Pattern:
- Purpose: Enable dynamic changes in system behavior and structure by making the system self-aware.
- Components:
- Meta Level: Encapsulates system properties for adaptation (e.g., user configurations).
- Base Level: Contains application logic that adapts based on meta-level changes.
- Applications: Used in systems with dynamic UI changes (e.g., shopping websites or banking apps).
Layered Architecture:
- Components are organized into layers based on their roles and levels of abstraction
- Layers include protocols, functionalities, or services for other layers.
- Communication typically occurs between adjacent layers.
- Simplifies the design by decomposing systems into manageable parts.
- Promotes modularity, reusability, and maintainability.
Design Principles:
- Start with abstraction criteria.
- Define number of layers and assign tasks to each.
- Specify layer interfaces and refine the layering process.
Layered Pattern - Implementation:
- Define the abstraction criterion
- Determine the number of abstraction levels
- Name the layers and assign tasks to each of them
- Specify the services
- Refine the layering
- Specify an interface for each layer
- Structure individual layers
- Specify communication between adjacent layers
- Decouple adjacent layers
- Design an error-handling strategy
Bad Smells in Code: Indicators of structural issues that may lead to bugs or make the code hard to maintain,
which are indicators of poor design or structure, signaling the need for refactoring.
-
Code Smells and Remedies:
- Long Methods: Break into smaller methods (extract method).
- Large Classes: Separate responsibilities into smaller, more manageable classes.
- Duplicate Code: Combine into a single method/class to improve reusability.
- Message Chains: Replace with direct delegation or use polymorphism.
Importance of Testing in Design: Incorporating testing in the design stage allows for incremental testing, reducing debugging time and preventing issues from escalating.
Where to Locate Tests?
- Within classes themselves.
- Through a separate test class hierarchy if embedding tests in classes is cumbersome.
How to Incorporate Testing?
- Create and frequently run localized unit tests
- Develop testing frameworks incrementally.
Types of Tests:
- Unit Tests: Validate individual class methods and features.
- Functional Tests: Test the system as a whole to ensure the software works as expected.
Focus on Boundary Conditions:
- Test edge cases to identify potential errors early.
-
Cross-Cutting Concerns: Aspects that affect multiple parts of the software, such as logging or error handling, which cannot be isolated within a single module
-
Cross-Cutting Concerns which are aspects of a software system that affect multiple modules and cannot easily be encapsulated within a single component.
Overview:
- Cross-cutting concerns cannot be neatly separated into modular components because they affect multiple classes, modules, or even the entire system.
- Examples include logging, authentication, server-client communication, and real-time synchronization in multiplayer games.
Challenges with Cross-Cutting Concerns:
- Tangling: Multiple modules are tightly coupled, leading to complex dependencies.
- Scattering: Logic for a single concern is distributed across various parts of the system.
- Solutions involve careful planning, modular design, and often trade-offs in complexity.
- Cross-cutting concerns can lead to tightly coupled systems (entanglement).
- They make extensions and updates challenging.
Importance of Cross-Cutting Concerns:
- They influence the design, modularity, and maintainability of a system.
- Addressing them ensures better scalability, fairness, and real-time functionality.
When is C3 worrisome
Peer Concerns in Tetris:
- Interaction between shapes, shadows, and the board creates complex dependencies.
Tangled Concerns: Overlap or interdependence in the functionality of related modules, making updates complex.
- Occurs when different entities’ behaviors are interconnected in complex ways.
- Example: Shadow moving left/right and climbing up based on the board and piece.
Shattered Concerns:
- When a concern is spread across multiple modules, leading to a lack of modularity.
- When responsibilities are split across entities like shapes, shadows, and the board, making them tightly coupled.
Tangling and Scattering:
- Tangling: Dependencies across modules increase complexity.
- Scattering: Code duplication across components reduces maintainability.
Intrusive Extensions:- Adding a shadow to Tetris shapes requires changes to both the shape and board classes, showcasing a cross-cutting concern.
-
Encapsulation’s Role: Encapsulation controls access to an object's state, preserving its integrity and enforcing information hiding.
-
- Separation of Interface and Implementation: A principle ensuring that how something is done can change independently of what it does.
-
- Modularity helps in managing complexity by dividing a system into distinct, self-contained components that can be developed and tested independently.
-
Software Design Principles (SDP): Focus on achieving modularity, efficiency, and adaptability, ensuring principles are sound, complete, and stable over time.
-
Iterative Refinement and Modularity: Iterative processes refine design principles, where modularity fosters independent components with minimal interdependency.
-
Conceptual Integrity: A core SDP, emphasizing the importance of cohesion in design to avoid premature decisions and ensure adaptability.
Conceptual Integrity: Consistency and clarity in design principles and structure, maintained across the software for coherence and adaptability.
-
Describe the what to the user, that is, whoever is going to use the services. Then prescribe the constraints on how to the implemented
-
Why Design for Reuse? Reduces cost by reusing existing components, ensuring long-term flexibility.
-
Two Hat Method: A metaphor where developers switch between adding new functionality and refactoring, not doing both simultaneously.
-
Magic Numbers: Hardcoded numeric values in code without context, which should be replaced by descriptive constants.
-
Bad Design Example:
- The bad design involves Tetrominoes in a game (e.g., Tetris), where a falling piece is controlled by the board. The interaction is complex and tangled, with no clear separation of concerns, making it hard to maintain and modify.
- Problems: The game engine has to control both the board and the falling piece, creating a rigid structure. This violates the principle of modularity and leads to entangled code that is hard to scale and manage.
Aspect-Oriented Programming (AOP):
- Programming paradigm addressing cross-cutting concerns.
- Enhances modularity by separating these concerns from core logic.
- Examples: AspectJ (Java-based), Adaptive Programming.
Benefits of AOD:
- Improved Modularity: Separates core logic from concerns like logging or security.
- Consistency: Ensures changes to one concern affect all related modules.
- Traceability: Simplifies navigation between design and code.
Aspect-Oriented Design (AOD): focuses on modularizing cross-cutting concerns that span multiple modules, ensuring these concerns are managed in a coordinated and modular manner. AOD aims to enhance modularity, reducing tangling (overlapping concerns in the same module) and scattering (spread of a single concern across multiple modules). It leverages aspects to seamlessly incorporate additional behaviors into existing designs without disrupting the core functionality.
Key techniques / solutions include:
- Aspect Orientation: Provides mechanisms for modularizing cross-cutting concerns.
- Intertype Declarations: Facilitate the extension of attributes and behaviors across types.
- Advices: Define specific actions at designated extension points. The action taken when a pointcut is reached (e.g., "before", "after", or "around" certain events).
- Pointcuts: Identify where cross-cutting concerns intersect with base functionality. A specific point in the program where additional behavior (advice) is applied.
- Frameworks: Tools like AspectJ, AspectWerkz, and JBoss-AOP assist in implementing AOD in object-oriented languages.
- Intrusive Extension: Modifications that require changes in multiple parts of the system due to tight coupling, e.g., adding new Tetris shapes.
-
Tangling:
- Overlapping of multiple concerns in a single module.
- Leads to increased complexity and reduced modularity.
Scattering:
- A concern being spread across multiple modules, leading to redundant or inconsistent implementations.
Aspect:
- A module that encapsulates a cross-cutting concern.
- Example: In a banking system, aspects like transaction logging and auditing.
Advice:
- Code that defines actions to be taken at specified points in the execution of a program.
Pointcuts:
- Specific points in the program where aspects are applied.
Intertype Declarations:
- Mechanisms to add attributes, methods, or behaviors to existing classes dynamically.
-
Service Orientation:
- Service orientation is crucial in distributed systems because it organizes how different entities (like clients and servers) communicate to offer services across a network.
- Clients and servers are identified and interact through different protocols.
Distributed Systems:
- A distributed system is a collection of physically separate, possibly heterogeneous networked systems. These systems communicate with each other and offer shared resources over the network.
- Examples include email services (like Hotmail, Gmail), messaging apps, and even older systems like paper mail.
- Distributed software design, which will facilitate the services will have to address these issues, concurrency, communication, fault tolerance.
- Service oriented design methods will seek to address these three issues systematically.
Architectural Models:
- Client-Server: One entity provides services; others request them.
- Three-Tier Architecture: Adds a middleware layer for enhanced service integration.
- N-Tier Architecture: More complex, with multiple layers for better abstraction and service integration.
- Distributed objects: Then we can have everything offered as distributed objects, objects offering services. They may not be even named entities, except for what they are doing. Something like we don't have a postman, if you have seen from old times who wears that uniform of the post office, but there are so many couriers who can just carry the letters and other objects for you. Similarly, we have distributed objects.
Service-Oriented Architecture (SOA):
SOA is a way to build distributed software by utilizing web services, which are executed on distributed systems. It builds upon existing protocols such as HTTP, HTTPS, and SOAP, and enables service communication over networks. SOA can implement either a client-server model or peer-to-peer architecture.
Concurrency:
- Distributed systems often have to manage multiple tasks simultaneously. For instance, in multiplayer games, the server must track the game states of multiple players at once.
Communication:
- Systems communicate over a network. Various protocols help manage interactions, such as discovery protocols and session protocols.
- Concurrency and communication must be synchronized to avoid inconsistencies.
Fault Tolerance:
- Fault tolerance ensures that the system continues to function even when parts of it fail. If a client disconnects or an error occurs, other clients should not be affected.
- Example: In multiplayer games, if one player disconnects, it shouldn't affect the other players' experience.
Fairness:
- The system must ensure fairness, especially in client-server interactions. For example, in online games, all clients should have the same game state and timing.
-
Client-Server Architecture: In this system, a client initiates requests, and the server responds with the requested services. The client must be familiar with the server's protocol and API but does not need to understand how the server works internally.
Peer-to-Peer Architecture: Here, devices connect directly to each other without a server acting as an intermediary, which is used in systems like file sharing.
N-Tier Architecture: This involves multiple layers or tiers in the system where each layer interacts with those above or below it in a client-server manner.
Browser-Server Model: A specific client-server model where the browser interacts with the server, sending HTTP requests like GET (retrieve data) or POST (send data).
-
Communication in Design: The transfer of ideas and expertise from designers to teams or users, often through models, sketches, or prototypes.
-
What is Software?
- Definition: Software is a non-physical set of instructions that runs on hardware, enabling computational tasks.
Software Properties (Brooks’ observations):
- Complexity: Diverse functionality and numerous execution states.
- Conformity: Must align with hardware/software it interacts with.
- Changeability: Constant demand for updates and maintenance.
- Invisibility: Software lacks tangible, visible forms, hindering communication.
-
-
-
Top Level Program Structure:
Headers, Packages, Modules, Namespaces