The Core Question: What Varies?

In software development, the enduring question is 'What varies?' This fundamental inquiry drives the creation and application of design patterns and the SOLID principles. A new resource, presented as a recall-first mind map, aims to demystify these concepts by grounding them in this central question. The mind map, authored by Rakshya K, draws heavily from Alexander Shvets's "Dive Into Design Patterns" (Refactoring.Guru, v2023) and uses Go for its examples, emphasizing interfaces and composition over classical inheritance.

The mind map organizes the problem space into three primary categories: creating objects, structuring objects, and communicating or assigning duties between objects. This high-level structure provides a framework for understanding where different design patterns and SOLID principles intervene.

Mermaid flowchart illustrating the central problem: What Varies?

Understanding the Mind Map's Structure

The mind map employs a 'recall-first' approach. Each node presents a question, followed by a hook, the conditions under which it applies ('when'), and a concise Go code skeleton. This method encourages active learning and retention, moving beyond passive consumption of information. The choice of Go is deliberate, leveraging its strong support for interfaces and composition, which often serve as more idiomatic and flexible alternatives to traditional object-oriented inheritance hierarchies found in languages like Java or C++.

The mind map breaks down the core problem into three main areas:

  • CREATE: This section addresses patterns and principles related to object instantiation and creation. It explores how to decouple the client from the concrete classes it needs to instantiate, ensuring flexibility when the creation process or the specific objects created need to change.
  • STRUCTURE: Here, the focus shifts to how objects are composed and how their relationships are managed. This involves patterns that help in building complex objects from simpler ones or in defining how different components interact to form a cohesive whole.
  • BEHAVE: This category covers patterns and principles that govern the runtime behavior of objects, particularly how they communicate with each other and how responsibilities are assigned. It delves into strategies for defining algorithms, managing state changes, and enabling flexible communication between objects.

Applying SOLID Principles within the Framework

The SOLID principles are foundational to building maintainable, scalable, and understandable object-oriented systems. This mind map integrates them directly into the 'what varies' framework:

  • Single Responsibility Principle (SRP): This principle aligns with the idea that a module or class should have only one reason to change. Within the mind map's structure, SRP helps identify which parts of the system are most likely to change and ensures that these changes are localized. For instance, if a class handles both data creation and data formatting, it has two reasons to change, violating SRP. The mind map encourages separating these concerns.
  • Open/Closed Principle (OCP): OCP states that software entities (classes, modules, functions) should be open for extension but closed for modification. This principle directly addresses the 'what varies' problem by providing mechanisms (like interfaces or abstract classes) to extend behavior without altering existing, stable code. If a system needs to add new types of objects or new behaviors, OCP guides how to do this cleanly.
  • Liskov Substitution Principle (LSP): LSP ensures that subtypes can be substituted for their base types without altering the correctness of the program. When dealing with inheritance or interface implementation, LSP is crucial for maintaining predictable behavior. If a subclass or implementing type behaves unexpectedly when used in place of its parent type or interface, it indicates a violation that can lead to bugs.
  • Interface Segregation Principle (ISP): ISP suggests that clients should not be forced to depend on interfaces they do not use. This principle encourages breaking down large, monolithic interfaces into smaller, more specific ones. In the context of 'what varies,' ISP helps to isolate the varying parts, ensuring that clients only depend on the specific contracts they need, thereby reducing coupling and the impact of changes.
  • Dependency Inversion Principle (DIP): DIP advocates for depending on abstractions rather than concretions. This is a cornerstone of flexible design. By depending on interfaces (abstractions) rather than concrete implementations, the system becomes more adaptable. If the concrete implementation needs to change or be swapped out, the dependent code, which relies on the abstraction, remains unaffected. This directly tackles the 'what varies' by making the dependencies themselves variable through abstraction.

Design Patterns as Solutions to Variation

The mind map categorizes design patterns based on their primary purpose, aligning with the 'CREATE', 'STRUCTURE', and 'BEHAVE' framework. Each pattern offers a specific solution to a recurring problem related to managing variation.

Creational Patterns (CREATE)

These patterns deal with object creation mechanisms, abstracting the process to increase flexibility. Examples include:

  • Factory Method: Defers instantiation to subclasses.
  • Abstract Factory: Provides an interface for creating families of related objects.
  • Builder: Separates the construction of a complex object from its representation.
  • Prototype: Creates new objects by cloning existing ones.
  • Singleton: Ensures a class only has one instance and provides a global point of access.

These patterns help manage variation in *how* objects are created, *which* objects are created, and *when* they are created.

Structural Patterns (STRUCTURE)

These patterns are concerned with class and object composition. They help in forming larger structures from smaller ones while keeping these structures flexible.

  • Adapter: Converts the interface of a class into another interface clients expect.
  • Bridge: Decouples an abstraction from its implementation so that the two can vary independently.
  • Composite: Composes objects into tree structures to represent part-whole hierarchies.
  • Decorator: Attaches additional responsibilities to an object dynamically.
  • Facade: Provides a simplified interface to a complex subsystem.
  • Flyweight: Uses sharing to support large numbers of fine-grained objects efficiently.
  • Proxy: Acts as a surrogate or placeholder for another object to control access to it.

These patterns address variation in how objects are assembled and how they interact structurally.

Behavioral Patterns (BEHAVE)

These patterns are concerned with algorithms and the assignment of responsibilities between objects. They characterize how classes or objects interact and distribute responsibility.

  • Chain of Responsibility: Avoids coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.
  • Command: Encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
  • Interpreter: Defines a representation for a grammar along with an interpreter that uses the representation to interpret sentences in the grammar.
  • Iterator: Provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
  • Mediator: Defines an object that encapsulates how a set of objects interact.
  • Memento: Captures and externalizes an object's internal state so that the object can be restored to this state later.
  • Observer: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
  • State: Allows an object to alter its behavior when its internal state changes.
  • Strategy: Defines a family of algorithms, encapsulates each one, and makes them interchangeable.
  • Template Method: Defines the skeleton of an algorithm in an operation, deferring some steps to subclasses.
  • Visitor: Represents an operation to be performed on the elements of an object structure.

These patterns manage variation in how objects perform tasks and interact dynamically.

The Value of a Go Implementation

Using Go for these examples is particularly insightful. Go's interfaces provide a powerful mechanism for achieving polymorphism and decoupling, often serving the same role as abstract classes or interfaces in other languages, but with a different, composition-oriented philosophy. The absence of classical inheritance in Go forces developers to think more critically about composition and delegation, which are core to many design patterns. This mind map, by illustrating these patterns in Go, offers a modern perspective that can be highly beneficial for developers working in Go or those looking to understand design principles through a different lens.

By centralizing the discussion around 'what varies,' this mind map provides a cohesive and practical way to understand the interconnectedness of design patterns and SOLID principles. It moves beyond rote memorization, encouraging a deeper understanding of the underlying problems that these established solutions address.