Categories
Software Engineering

DI – Dependency inversion principle of SOLID object-oriented design

“In object-oriented design, the dependency inversion principle is a specific form of loosely coupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details. The principle states:[1]” (WP)

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g., interfaces).
  2. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.
SOLID
Principles of Object-Oriented Design
SSingle responsibility principle – SRP
OOpen–closed
LLiskov substitution principle – LSP
IInterface segregation principle – ISP
DDependency inversion – DI

“By dictating that both high-level and low-level objects must depend on the same abstraction, this design principle inverts the way some people may think about object-oriented programming.[2]” (WP)

“The idea behind points A and B of this principle is that when designing the interaction between a high-level module and a low-level one, the interaction should be thought of as an abstract interaction between them. This not only has implications on the design of the high-level module, but also on the low-level one: the low-level one should be designed with the interaction in mind and it may be necessary to change its usage interface.” (WP)

“In many cases, thinking about the interaction in itself as an abstract concept allows the coupling of the components to be reduced without introducing additional coding patterns, allowing only a lighter and less implementation-dependent interaction schema.” (WP)

“When the discovered abstract interaction schema(s) between two modules is/are generic and generalization makes sense, this design principle also leads to the following dependency inversion coding pattern.” (WP)

Traditional layers pattern

In conventional application architecture, lower-level components (e.g., Utility Layer) are designed to be consumed by higher-level components (e.g., Policy Layer) which enable increasingly complex systems to be built. In this composition, higher-level components depend directly upon lower-level components to achieve some task. This dependency upon lower-level components limits the reuse opportunities of the higher-level components.[1]

Traditional Layers Pattern.png

The goal of the dependency inversion pattern is to avoid this highly coupled distribution with the mediation of an abstract layer, and to increase the re-usability of higher/policy layers.

Dependency inversion pattern

With the addition of an abstract layer, both high- and lower-level layers reduce the traditional dependencies from top to bottom. Nevertheless, the “inversion” concept does not mean that lower-level layers depend on higher-level layers. Both layers should depend on abstractions that draw the behavior needed by higher-level layers.

DIPLayersPattern.png

In a direct application of dependency inversion, the abstracts are owned by the upper/policy layers. This architecture groups the higher/policy components and the abstractions that define lower services together in the same package. The lower-level layers are created by inheritance/implementation of these abstract classes or interfaces.[1]

The inversion of the dependencies and ownership encourages the re-usability of the higher/policy layers. Upper layers could use other implementations of the lower services. When the lower-level layer components are closed or when the application requires the reuse of existing services, it is common that an Adapter mediates between the services and the abstractions.

Dependency inversion pattern generalization

In many projects the dependency inversion principle and pattern are considered as a single concept that should be generalized, i.e., applied to all interfaces between software modules. There are at least two reasons for that:

  1. It is simpler to see a good thinking principle as a coding pattern. Once an abstract class or an interface has been coded, the programmer may say: “I have done the job of abstraction”.
  2. Because many unit testing tools rely on inheritance to accomplish mocking, the usage of generic interfaces between classes (not only between modules when it makes sense to use generality) became the rule.

If the mocking tool used relies only on inheritance, it may become necessary to widely apply the dependency inversion pattern. This has major drawbacks:

  1. Merely implementing an interface over a class isn’t sufficient to reduce coupling; only thinking about the potential abstraction of interactions can lead to a less coupled design.
  2. Implementing generic interfaces everywhere in a project makes it harder to understand and maintain. At each step the reader will ask themself what are the other implementations of this interface and the response is generally: only mocks.
  3. The interface generalization requires more plumbing code, in particular factories that generally rely on a dependency-injection framework.
  4. Interface generalization also restricts the usage of the programming language.

Generalization restrictions

The presence of interfaces to accomplish the Dependency Inversion Pattern (DIP) has other design implications in an object-oriented program:

  • All member variables in a class must be interfaces or abstracts.
  • All concrete class packages must connect only through interface or abstract class packages.
  • No class should derive from a concrete class.
  • No method should override an implemented method.[1]
  • All variable instantiation requires the implementation of a creational pattern such as the factory method or the factory pattern, or the use of a dependency-injection framework.

Interface mocking restrictions

Using inheritance-based mocking tools also introduces restrictions:

  • Static externally visible members should systematically rely on dependency injection making them far harder to implement.
  • All testable methods should become an interface implementation or an override of an abstract definition.

Future directions

Principles are ways of thinking. Patterns are common ways to solve problems. Coding patterns may be missing programming language features.

  • Programming languages will continue to evolve to allow them to enforce stronger and more precise usage contracts in at least two directions: enforcing usage conditions (pre-, post- and invariant conditions) and state-based interfaces. This will probably encourage and potentially simplify a stronger application of the dependency inversion pattern in many situations.
  • More and more mocking tools now use dependency-injection to solve the problem of replacing static and non virtual members. Programming languages will probably evolve to generate mocking-compatible bytecode. One direction will be to restrict the usage of non-virtual members. The other one will be to generate, at least in test situations, bytecode allowing non-inheritance based mocking.

Implementations

Two common implementations of DIP use similar logical architecture but with different implications.

A direct implementation packages the policy classes with service abstracts classes in one library. In this implementation high-level components and low-level components are distributed into separate packages/libraries, where the interfaces defining the behavior/services required by the high-level component are owned by, and exist within the high-level component’s library. The implementation of the high-level component’s interface by the low-level component requires that the low-level component package depend upon the high-level component for compilation, thus inverting the conventional dependency relationship.

Dependency inversion.png

Figures 1 and 2 illustrate code with the same functionality, however in Figure 2, an interface has been used to invert the dependency. The direction of dependency can be chosen to maximize policy code reuse, and eliminate cyclic dependencies.

In this version of DIP, the lower layer component’s dependency on the interfaces/abstracts in the higher-level layers makes re-utilization of the lower layer components difficult. This implementation instead ″inverts″ the traditional dependency from top-to-bottom to the opposite, from bottom-to-top.

A more flexible solution extracts the abstract components into an independent set of packages/libraries:

DIPLayersPattern v2.png

The separation of each layer into its own package encourages re-utilization of any layer, providing robustness and mobility.[1]

Examples

Genealogical module

A genealogical system may represent relationships between people as a graph of direct relationships between them (father-son, father-daughter, mother-son, mother-daughter, husband-wife, wife-husband, etc.). This is very efficient and extensible, as it is easy to add an ex-husband or a legal guardian.

But some higher-level modules may require a simpler way to browse the system: any person may have children, parents, siblings (including half-brothers and -sisters or not), grandparents, cousins, and so on.

Depending on the usage of the genealogical module, presenting common relationships as distinct direct properties (hiding the graph) will make the coupling between a higher-level module and the genealogical module much lighter and allow one to change the internal representation of the direct relationships completely without any effect on the modules using them. It also permits embedding exact definitions of siblings or uncles in the genealogical module, thus enforcing the single responsibility principle.

Finally, if the first extensible generalized graph approach seems the most extensible, the usage of the genealogical module may show that a more specialized and simpler relationship implementation is sufficient for the application(s) and helps create a more efficient system.

In this example, abstracting the interaction between the modules leads to a simplified interface of the lower-level module and may lead to a simpler implementation of it.

Remote file server client

Imagine you have to implement a client to a remote file server (FTP, cloud storage …). You may think of it as a set of abstract interfaces:

  1. Connection/Disconnection (a connection persistence layer may be needed)
  2. Folder/tags creation/rename/delete/list interface
  3. File creation/replacement/rename/delete/read interface
  4. File searching
  5. Concurrent replacement or delete resolution
  6. File history management …

If both local files and remote files offers the same abstract interfaces, any high-level module using local files and fully implementing the dependency inversion pattern will be able to access local and remote files indiscriminately.

Local disk will generally use folder, remote storage may use folder and/or tags. You have to decide how to unify them if possible.

On remote file we may have to use only create or replace: remote files update do not necessarily make sense because random update is too slow comparing local file random update and may be very complicated to implement). On remote file we may need partial read and write (at least inside the remote file module to allow download or upload to resume after a communication interruption), but random read isn’t adapted (except if a local cache is used).

File searching may be pluggable : file searching can rely on the OS or in particular for tag or full text search, be implemented with distinct systems (OS embedded, or available separately).

Concurrent replacement or delete resolution detection may impact the other abstract interfaces.

When designing the remote file server client for each conceptual interface you have to ask yourself the level of service your high level modules require (not necessary all of them) and not only how to implement the remote file server functionalities but maybe how to make the file services in your application compatible between already implemented file services (local files, existing cloud clients) and your new remote file server client.

Once you have designed the abstract interfaces required, your remote file server client should implement these interfaces. And because you probably restricted some local functionalities existing on local file (for example file update), you may have to write adapters for local or other existing used remote file access modules each offering the same abstract interfaces. You also have to write your own file access enumerator allowing to retrieve all file compatible systems available and configured on your computer.

Once you do that, your application will be able to save its documents locally or remotely transparently. Or simpler, the high level module using the new file access interfaces can be used indistinctly in local or remote file access scenarios making it reusable.

Remark: many OSes have started to implement these kind of functionalities and your work may be limited to adapt your new client to this already abstracted models.

In this example, thinking of the module as a set of abstract interfaces, and adapting other modules to this set of interfaces, allows you to provide a common interface for many file storage systems.

Model View Controller

Example of DIP

UI and ApplicationLayer packages contains mainly concrete classes. Controllers contains abstracts/interface types. UI has an instance of ICustomerHandler. All packages are physically separated. In the ApplicationLayer there is a concrete implementation that Page class will use. Instances of this interface are created dynamically by a Factory (possibly in the same Controllers package). The concrete types, Page and CustomerHandler, don’t depend on each other; both depend on ICustomerHandler.

The direct effect is that the UI doesn’t need to reference the ApplicationLayer or any concrete package that implements the ICustomerHandler. The concrete class will be loaded using reflection. At any moment the concrete implementation could be replaced by another concrete implementation without changing the UI class. Another interesting possibility is that the Page class implements an interface IPageViewer that could be passed as an argument to ICustomerHandler methods. Then the concrete implementation could communicate with UI without a concrete dependency. Again, both are linked by interfaces.

Related patterns

Applying the dependency inversion principle can also be seen as an example of the adapter pattern, i.e. the high-level class defines its own adapter interface which is the abstraction that the other high-level classes depend on. The adaptee implementation also depends on the adapter interface abstraction (of course, since it implements its interface) while it can be implemented by using code from within its own low-level module. The high-level has no dependency on the low-level module since it only uses the low-level indirectly through the adapter interface by invoking polymorphic methods to the interface which are implemented by the adaptee and its low-level module.

Various patterns such as Plugin, Service Locator, or Dependency injection are employed to facilitate the run-time provisioning of the chosen low-level component implementation to the high-level component.

History

The dependency inversion principle was postulated by Robert C. Martin and described in several publications including the paper Object Oriented Design Quality Metrics: an analysis of dependencies,[3] an article appearing in the C++ Report in May 1996 entitled The Dependency Inversion Principle,[4] and the books Agile Software Development, Principles, Patterns, and Practices,[1] and Agile Principles, Patterns, and Practices in C#.

See also

References

  1. a b c d e f Martin, Robert C. (2003). Agile Software Development, Principles, Patterns, and Practices. Prentice Hall. pp. 127–131. ISBN 978-0135974445.
  2. ^ Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (paperback). 1. O’REILLY. ISBN 978-0-596-00712-6. Retrieved 2012-06-21.
  3. ^ Martin, Robert C. (October 1994). “Object Oriented Design Quality Metrics: An analysis of dependencies” (PDF). Retrieved 2016-10-15.
  4. ^ Martin, Robert C. (May 1996). “The Dependency Inversion Principle” (PDF). C++ Report. Archived from the original (PDF) on 2011-07-14.

External links

Categories

” (WP)

Sources:

Fair Use Sources:

Categories
C++ Cloud DevOps DevSecOps-Security-Privacy Software Engineering

Design Patterns: Elements of Reusable Object-Oriented Software, Gang of Four (GoF), 1994

See also: Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software, 2nd Edition, by Eric Freeman and Elisabeth Robson, 2021

Fair Use Source: B000SEIBB8 (GoF)

Design Patterns: Elements of Reusable Object-Oriented Software, 1st Edition, by Gamma Erich, Helm Richard, Johnson Ralph, Vlissides John

Design Patterns: Elements of Reusable Object-Oriented Software (1994) is a software engineering book describing software design patterns. The book was written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, with a foreword by Grady Booch. The book is divided into two parts, with the first two chapters exploring the capabilities and pitfalls of object-oriented programming, and the remaining chapters describing 23 classic software design patterns. The book includes examples in C++ and Smalltalk.” (WP)

“It has been influential to the field of software engineering and is regarded as an important source for object-oriented design theory and practice. More than 500,000 copies have been sold in English and in 13 other languages. The authors are often referred to as the Gang of Four (GoF).[1]” (WP)

Capturing a wealth of experience about the design of object-oriented software, four top-notch designers present a catalog of simple and succinct solutions to commonly occurring design problems. Previously undocumented, these 23 patterns allow designers to create more flexible, elegant, and ultimately reusable designs without having to rediscover the design solutions themselves.

The authors begin by describing what patterns are and how they can help you design object-oriented software. They then go on to systematically name, explain, evaluate, and catalog recurring designs in object-oriented systems. With Design Patterns as your guide, you will learn how these important patterns fit into the software development process, and how you can leverage them to solve your own design problems most efficiently.

Each pattern describes the circumstances in which it is applicable, when it can be applied in view of other design constraints, and the consequences and trade-offs of using the pattern within a larger design. All patterns are compiled from real systems and are based on real-world examples. Each pattern also includes code that demonstrates how it may be implemented in object-oriented programming languages like C++ or Smalltalk.

Editorial Reviews

Design Patterns is a modern classic in the literature of object-oriented development, offering timeless and elegant solutions to common problems in software design. It describes patterns for managing object creation, composing objects into larger structures, and coordinating control flow between objects. The book provides numerous examples where using composition rather than inheritance can improve the reusability and flexibility of code. Note, though, that it’s not a tutorial but a catalog that you can use to find an object-oriented design pattern that’s appropriate for the needs of your particular application–a selection for virtuoso programmers who appreciate (or require) consistent, well-engineered object-oriented designs

Book Details

  • ASIN: B000SEIBB8
  • Publisher: Addison-Wesley Professional; 1st edition (October 31, 1994)
  • Publication date: October 31, 1994
  • Print length: 568 pages

Sources:

Fair Use Sources:

Categories
Cloud DevOps DevSecOps-Security-Privacy Software Engineering

Head First Design Patterns

See also: Design Patterns: Elements of Reusable Object-Oriented Software, Gang of Four (GoF), 1994

Fair Use Source: B08P3X99QP (HFDP)

See: Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software, 2nd Edition, by Eric Freeman and Elisabeth Robson, Kathy Sierra, and Bert Bates, 2021

What will you learn from this book?

You know you don’t want to reinvent the wheel, so you look to Design Patterns: the lessons learned by those who’ve faced the same software design problems. With Design Patterns, you get to take advantage of the best practices and experience of others so you can spend your time on something more challenging. Something more fun. This book shows you the patterns that matter, when to use them and why, how to apply them to your own designs, and the object-oriented design principles on which they’re based. Join hundreds of thousands of developers who’ve improved their object-oriented design skills through Head First Design Patterns.

What’s so special about this book?

If you’ve read a Head First book, you know what to expect: a visually rich format designed for the way your brain works. With Head First Design Patterns, 2E you’ll learn design principles and patterns in a way that won’t put you to sleep, so you can get out there to solve software design problems and speak the language of patterns with others on your team.

Book Details

  • ASIN: B08P3X99QP
  • ISBN: 978-1-492-07800-5
  • Publisher: O’Reilly Media; 2nd edition (November 24, 2020)
  • Publication date: November 24, 2020
  • Print length: 1156 pages
  • Printing History: October 2004: First edition
  • December 2020: Second edition
  • Release History: 2020-11-10 First release

Dedication:

“To the Gang of Four, whose insight and expertise in capturing and communicating Design Patterns has changed the face of software design forever, and bettered the lives of developers throughout the world. But seriously, when are we going to see a second edition? After all, it’s been only twenty-five years.” (HFDP)

” (HFDP)

Sources:

Fair Use Sources:

Categories
C Language C# .NET C++ Cloud DevOps Django Web Framework Flask Web Framework Go Programming Language Java JavaScript Kotlin PowerShell Python Ruby Software Engineering Spring Framework Swift TypeScript

Software design pattern

In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design. It is not a finished design that can be transformed directly into source or machine code. Rather, it is a description or template for how to solve a problem that can be used in many different situations. Design patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system.

Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Patterns that imply mutable state may be unsuited for functional programming languages, some patterns can be rendered unnecessary in languages that have built-in support for solving the problem they are trying to solve, and object-oriented patterns are not necessarily suitable for non-object-oriented languages.

Design patterns may be viewed as a structured approach to computer programming intermediate between the levels of a programming paradigm and a concrete algorithm.

In a recent review study, Wedyan and Abufakher investigate design patterns and software quality and conclude: “Our study has shown that the primary studies provide an empirical evidence on the positive effect of documentation of designs pattern instances on program comprehension, and therefore, maintainability. While this result is not surprising, it has, however, two indications. First, developers should pay more effort to add such documentation, even if in the form of simple comments in the source code. Second, when comparing results of different studies, the effect of documentation has to be considered.”[1]

Categories
Cloud DevOps DevSecOps-Security-Privacy Software Engineering

! Template Design Pattern

” (GoF)

” (WP)

Sources:

Fair Use Sources:

Categories
Cloud DevOps Software Engineering

DDD Domain-Driven Design

Return to Timeline of the History of Computers, Networking

Domain-driven design (DDD) is the concept that the structure and language of software code (class names, class methods, class variables) should match the business domain. For example, if a software processes loan applications, it might have classes such as LoanApplication and Customer, and methods such as AcceptOffer and Withdraw.

DDD connects the implementation to an evolving model.[1]

Domain-driven design is predicated on the following goals:

  • placing the project’s primary focus on the core domain and domain logic;
  • basing complex designs on a model of the domain;
  • initiating a creative collaboration between technical and domain experts to iteratively refine a conceptual model that addresses particular domain problems.

The term was coined by Eric Evans in his book of the same title.[2]

Concepts

Concepts of the model include:ContextThe setting in which a word or statement appears that determines its meaning;DomainA sphere of knowledge (ontology), influence, or activity. The subject area to which the user applies a program is the domain of the software;ModelA system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain;Ubiquitous LanguageA language structured around the domain model and used by all team members to connect all the activities of the team with the software.

Strategic domain-driven design

Semantic network of patterns in strategic domain-driven design.

Ideally, it would be preferable to have a single, unified model. While this is a noble goal, in reality it typically fragments into multiple models. It is useful to recognize this fact of life and work with it.

Strategic Design is a set of principles for maintaining model integrity, distilling the Domain Model, and working with multiple models.[citation needed]

Bounded context

Multiple models are in play on any large project. Yet when code based on distinct models is combined, software becomes buggy, unreliable, and difficult to understand. Communication among team members becomes confusing. It is often unclear in what context a model should not be applied.

Therefore: Explicitly define the context within which a model applies. Explicitly set boundaries in terms of team organization, usage within specific parts of the application, and physical manifestations such as code bases and database schemas. Keep the model strictly consistent within these bounds, but don’t be distracted or confused by issues outside and inside.

Continuous integration

When a number of people are working in the same bounded context, there is a strong tendency for the model to fragment. The bigger the team, the bigger the problem, but as few as three or four people can encounter serious problems. Yet breaking down the system into ever-smaller contexts eventually loses a valuable level of integration and coherency.

Therefore: Institute a process of merging all code and other implementation artifacts frequently, with automated tests to flag fragmentation quickly. Relentlessly exercise the ubiquitous language to hammer out a shared view of the model as the concepts evolve in different people’s heads.

Context map

An individual bounded context leaves some problems in the absence of a global view. The context of other models may still be vague and in flux.

People on other teams won’t be very aware of the context bounds and will unknowingly make changes that blur the edges or complicate the interconnections. When connections must be made between different contexts, they tend to bleed into each other.

Therefore: Identify each model in play on the project and define its bounded context. This includes the implicit models of non-object-oriented subsystems. Name each bounded context, and make the names part of the ubiquitous language. Describe the points of contact between the models, outlining explicit translation for any communication and highlighting any sharing. Map the existing terrain.

Building blocks

In the book Domain-Driven Design,[2] a number of high-level concepts and practices are articulated, such as ubiquitous language meaning that the domain model should form a common language given by domain experts for describing system requirements, that works equally well for the business users or sponsors and for the software developers. The book is very focused on describing the domain layer as one of the common layers in an object-oriented system with a multilayered architecture. In DDD, there are artifacts to express, create, and retrieve domain models:EntityAn object that is not defined by its attributes, but rather by a thread of continuity and its identity.Example: Most airlines distinguish each seat uniquely on every flight. Each seat is an entity in this context. However, Southwest Airlines, EasyJet and Ryanair do not distinguish between every seat; all seats are the same. In this context, a seat is actually a value object.Value objectAn object that contains attributes but has no conceptual identity. They should be treated as immutable.Example: When people exchange business cards, they generally do not distinguish between each unique card; they are only concerned about the information printed on the card. In this context, business cards are value objects.AggregateA collection of objects that are bound together by a root entity, otherwise known as an aggregate root. The aggregate root guarantees the consistency of changes being made within the aggregate by forbidding external objects from holding references to its members.Example: When you drive a car, you do not have to worry about moving the wheels forward, making the engine combust with spark and fuel, etc.; you are simply driving the car. In this context, the car is an aggregate of several other objects and serves as the aggregate root to all of the other systems.Domain EventA domain object that defines an event (something that happens). A domain event is an event that domain experts care about.ServiceWhen an operation does not conceptually belong to any object. Following the natural contours of the problem, you can implement these operations in services. See also Service (systems architecture).RepositoryMethods for retrieving domain objects should delegate to a specialized Repository object such that alternative storage implementations may be easily interchanged.FactoryMethods for creating domain objects should delegate to a specialized Factory object such that alternative implementations may be easily interchanged.

Disadvantages

In order to help maintain the model as a pure and helpful language construct, the team must typically implement a great deal of isolation and encapsulation within the domain model. Consequently, a system based on domain-driven design can come at a relatively high cost. While domain-driven design provides many technical benefits, such as maintainability, Microsoft recommends that it be applied only to complex domains where the model and the linguistic processes provide clear benefits in the communication of complex information, and in the formulation of a common understanding of the domain.[3]

Relationship to other ideas

Object-oriented analysis and designAlthough, in theory, the general idea of DDD need not be restricted to object-oriented approaches, in practice DDD seeks to exploit the advantages that object-oriented techniques make possible. These include entities/aggregate roots as receivers of commands/method invocations and the encapsulation of state within foremost aggregate roots and on a higher architectural level, bounded contexts.Model-driven engineering (MDE) and Model-driven architecture (MDA)While DDD is compatible with MDA/MDE (where MDE can be regarded as a superset of MDA) the intent of the two concepts is somewhat different. MDA is concerned more with the means of translating a model into code for different technology platforms than with the practice of defining better domain models. The techniques provided by MDE (to model domains, to create DSLs to facilitate the communication between domain experts and developers,…) facilitate the application of DDD in practice and help DDD practitioners to get more out of their models. Thanks to the model transformation and code generation techniques of MDE, the domain model can be used not only to represent the domain but also to generate the actual software system that will be used to manage it. This picture shows a possible representation of DDD and MDE combined.Plain Old Java Objects (POJOs) and Plain Old CLR Objects (POCOs)POJOs and POCOs are technical implementation concepts, specific to Java and the .NET Framework respectively. However, the emergence of the terms POJO and POCO reflect a growing view that, within the context of either of those technical platforms, domain objects should be defined purely to implement the business behaviour of the corresponding domain concept, rather than be defined by the requirements of a more specific technology framework.The naked objects patternBased on the premise that if you have a good enough domain model, the user interface can simply be a reflection of this domain model; and that if you require the user interface to be a direct reflection of the domain model then this will force the design of a better domain model.[4]Domain-specific modeling (DSM)DSM is DDD applied through the use of Domain-specific languages.Domain-specific language (DSL)DDD does not specifically require the use of a DSL, though it could be used to help define a DSL and support methods like domain-specific multimodeling.Aspect-oriented programming (AOP)AOP makes it easy to factor out technical concerns (such as security, transaction management, logging) from a domain model, and as such makes it easier to design and implement domain models that focus purely on the business logic.Command Query Responsibility Segregation (CQRS)CQRS is an architectural pattern for separation of reads from writes, where the former is a Query and the latter is a Command. Commands mutate state and are hence approximately equivalent to method invocation on aggregate roots/entities. Queries read state but do not mutate it. CQRS is a derivative architectural pattern from the design pattern called Command and Query Separation (CQS) which was coined by Bertrand Meyer. While CQRS does not require DDD, domain-driven design makes the distinction between commands and queries explicit, around the concept of an aggregate root. The idea is that a given aggregate root has a method that corresponds to a command and a command handler invokes the method on the aggregate root. The aggregate root is responsible for performing the logic of the operation and yielding either a number of events or a failure (exception or execution result enumeration/number) response OR (if Event Sourcing (ES) is not used) just mutating its state for a persister implementation such as an ORM to write to a data store, while the command handler is responsible for pulling in infrastructure concerns related to the saving of the aggregate root’s state or events and creating the needed contexts (e.g. transactions).Event Sourcing (ES)An architectural pattern which warrants that your entities (as per Eric Evans’ definition) do not track their internal state by means of direct serialization or O/R mapping, but by means of reading and committing events to an event store. Where ES is combined with CQRS and DDD, aggregate roots are responsible for thoroughly validating and applying commands (often by means having their instance methods invoked from a Command Handler), and then publishing a single or a set of events which is also the foundation upon which the aggregate roots base their logic for dealing with method invocations. Hence, the input is a command and the output is one or many events which are transactionally (single commit) saved to an event store, and then often published on a message broker for the benefit of those interested (often the views are interested; they are then queried using Query-messages). When modeling your aggregate roots to output events, you can isolate the internal state even further than would be possible when projecting read-data from your entities, as is done in standard n-tier data-passing architectures. One significant benefit from this is that tooling such as axiomatic theorem provers (e.g. Microsoft Contracts and CHESS[5]) are easier to apply, as the aggregate root comprehensively hides its internal state. Events are often persisted based on the version of the aggregate root instance, which yields a domain model that synchronizes in distributed systems around the concept of optimistic concurrency.

Fair Use Sources:

Categories
Cloud Data Science - Big Data DevOps DevSecOps-Security-Privacy History Operating Systems Software Engineering

Software Design

Return to Timeline of the History of Computers, Networking

Software design is the process by which an agent creates a specification of a software artifact intended to accomplish goals, using a set of primitive components and subject to constraints.[1] Software design may refer to either “all the activity involved in conceptualizing, framing, implementing, commissioning, and ultimately modifying complex systems” or “the activity following requirements specification and before programming, as … [in] a stylized software engineering process.”[2]

Software design usually involves problem-solving and planning a software solution. This includes both a low-level component and algorithm design and a high-level, architecture design.

Fair Use Sources: