The key principles are:

  • Separation of concerns.

    • Divide your application into distinct features with as little overlap in functionality as possible. The important factor is minimization of interaction points to achieve high cohesion and low coupling.

    • However, separating functionality at the wrong boundaries can result in high coupling and complexity between features even though the contained functionality within a feature does not significantly overlap.

    • For example, ASP.NET MVC Framework (Model, View, Controller)

  • Single Responsibility principle.

    • Each component or module should be responsible for only a specific feature or functionality, or aggregation of cohesive functionality.

    • For example, ASP.NET MVC Framework (Model, View, Controller)

  • Principle of Least Knowledge (a.k.a. Law of Demeter or LoD).

    • A component or object should not know about internal details of other components or objects.

    • For example, In ASP.NET MVC Framework view is not aware of what Model or Controller are doing.

  • Don’t repeat yourself (DRY).

    • You should only need to specify intent in one place.

    • For example, in terms of application design, specific functionality should be implemented in only one component; the functionality should not be duplicated in any other component.

    • For example, In ASP.NET MVC Helper classes are used so that HTML code repetition can be removed.

  • Minimize upfront design.

    • Only design what is necessary.

    • In some cases, you may require upfront comprehensive design and testing if the cost of development or a failure in the design is very high. In other cases, especially for agile development, you can avoid big design upfront (BDUF).

    • If your application requirements are unclear, or if there is a possibility of the design evolving over time, avoid making a large design effort prematurely. This principle is sometimes known as YAGNI ("You ain’t gonna need it").

In general, Minimize the complexity by separating the design into different areas of concern.

For example,  the user interface (UI), business processing, and data access all represent different areas of concern.

Within each area, the components you design should focus on that specific area and should not mix code from other areas of concern.

For example, UI processing components should not include code that directly accesses a data source, but instead should use either business components or data access components to retrieve data.