Mastering Software Complexity: Design Principles and Real-World Patterns
This article explores why software complexity is inherent, examines cognitive challenges, and presents practical design principles—such as responsibility separation, layered abstraction, and change extensibility—illustrated with real-world examples from Spring MVC, MyBatis, and other frameworks, offering actionable insights for building maintainable systems.
1. Complexity is the inherent attribute of software
1.1 Complexity is inherent
As Brooks noted, software complexity is intrinsic, caused by four factors: domain complexity, development process management, pervasive flexibility, and modeling discrete system behavior.
Domain complexity
Managing development process complexity
Ubiquitous flexibility
Modeling discrete system behavior
Each factor poses challenges; for example, large systems consist of dozens of applications, making it hard for a single developer to grasp the whole system.
1.2 Cognitive complexity as a key factor
Cognitive complexity exceeds human capacity when codebases or application counts grow, making maintenance harder. Understanding common patterns can reduce cognitive load, as illustrated by a financial accounting case where business knowledge spans e‑commerce, payment, marketing, settlement, and funds.
2. Design methods to cope with complexity
2.1 Grasping patterns is fundamental
Patterns such as SOLID, GRASP, KISS, and layering guide design in complex systems.
2.2 General patterns
Three overarching categories: responsibility separation, layered abstraction, and change extensibility.
2.2.1 Responsibility separation
Two insights: a class should own the information it needs, and a class should do one thing. Examples include placing order‑amount calculation inside the Order class and applying the Single Responsibility Principle.
2.2.2 Layered abstraction
Typical three‑layer division: view, business logic, and data access. Example: Spring MVC abstracts parameter binding into POJOs, reducing repetitive code.
2.2.3 Change extensibility
Systems must anticipate change; techniques include configuration items, interfaces, abstract classes, interceptors, SPI, and plugins.
2.3 Six design experiences
2.3.1 Template method for invariant parts
Use a template method to fix common logic while allowing subclasses to implement variations. Example from Spring MVC HandlerMapping.
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
} public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// abstract method delegated to subclass
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// omitted code
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}2.3.2 Query‑command separation
Separate read (query) and write (command) responsibilities, e.g., Bean retrieval vs. Bean creation in Spring.
2.3.3 Configuration vs. execution domain separation
Configuration objects (e.g., RequestMappingInfo) differ from execution objects (e.g., HandlerMethod).
@RestController
public class UserController {
@RequestMapping(value = "/acquire", method = RequestMethod.GET)
public User getUser(@RequestParam("name") String name, @RequestParam("age") Integer age) {
return null;
}
}2.3.4 Encapsulating change
Spring uses BeanPostProcessor to add behavior before/after bean initialization.
public interface BeanPostProcessor {
// before initialization
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// after initialization
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}2.3.5 Responsibility chain for workflow
HttpClient implements a chain of handlers for retry, caching, redirection, socket usage, etc.
2.3.6 Abstraction for complex scenarios
AOP abstracts cross‑cutting concerns into aspects, pointcuts, and advice, enabling modular handling of logging, security, and other concerns.
3. Framework design case study
Spring MVC DispatcherServlet demonstrates responsibility separation (init vs. service) and extensibility via interceptors.
4. Cognition as the foundation
4.1 Business cognition
Understanding real‑world scenarios (e.g., Spring Bean scanning) reveals why frameworks are complex; multiple configuration sources and nested definitions increase difficulty.
4.2 Technical cognition
Designing an event dispatcher requires generic type resolution to avoid burdening users with manual handler mapping.
public class EventDispatcher {
private static List<Event> events = new ArrayList<>();
private static List<Handler> handlers = new ArrayList<>();
public static void addEvent(Event event) { events.add(event); }
public static void addHandler(Handler handler) { handlers.add(handler); }
public Object fire(Event event) throws Exception {
Handler handler = getHandler(event);
if (Objects.isNull(handler)) {
throw new Exception("No handler found for event " + event.getEventName());
}
return handler.handle(event);
}
private Handler getHandler(Event event) throws Exception {
for (Handler h : handlers) {
Type[] args = ((ParameterizedTypeImpl)h.getClass().getGenericInterfaces()[0])
.getActualTypeArguments();
if (Class.forName(((Class)args[0]).getName()).equals(event.getClass())) {
return h;
}
}
return null;
}
}5. Summary
The article presents principles and experiences for handling software complexity, emphasizing responsibility separation, layered abstraction, and change extensibility, and stresses that deep business and technical cognition is essential for effective design.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
