Roles

Roles

 

  • In a particular context with a particular set of influencing forces, there will be number of roles working for problem resolution.
  • Real world analogy would be Organizational structure of an Office. Each role has specific responsibilities and abstraction. Role at each level prepares the information needed and delegates sub tasks to appropriate roles in lower-level.
  • Software design focuses on strategical organization of components and decides which particular role must be implemented by which component.
  • It is not necessary that each role is played by a separate distinct component. A single component may take on multiple roles.
  • Structure of components (each having a specific role) should be designed to resolve the original problem keeping forces(non-functional requirements) in mind.
  • Communication between different components performing different roles should be simple with strict dependency boundaries. Unnecessary indirection levels should be avoided so that design is more flexible and more effective.
  • Consider the following dynamic model, in each subsystem there are three important roles(Components) a) Boundary b) Entities c) Control.
  • Boundary objects responsibility is restricted to take the service request from external system, validate data to be processed and pass the service request with data to the Control object. Control object controls the process flow for fulfilling the service request. Control object orchestrates the Entity Objects to perform the task.
  • Consider the following layered architecture model, which I got from the video :-https://www.youtube.com/watch?v=aZp7C971uC8&feature=youtube_gdata_player

  • Each layer has a fat interface which acts as a facade. Facade abstracts the internal components of subsystem. Allows the domain model to evolve. Can also act as secure layer, validating the caller and data in case of N-tier deployment.
  • Role of each layer (Analogy : Department of an office) & each component(Person in organization structure ) in a layer have specific roles and clear dependency firewalls.
  • In an organization, Seperation of Concerns at different levels of abstractions might be achieved as follows: Directory (boundary object) might take the operation requirement and orchestrate the activites and data managed by managers(of different departments) to complete the operation.
    In a software system, seperation of concerns at different levels (layers) of abstraction and at the same level of abstraction(different controllers in a layer) avoids ripple effects of modifications to different components. It facilitates concurrent development and allow independent evolution of components in each layer.

Analysis Paralysis for Mythical Completeness in Software Design

- Over analyzing requirements, prolonging "Analysis and Design Process" to achieve completeness of design is an Anti pattern in Software development.

- After initial analysis and design, it's better to create a POC (of alternate approaches) and analyze Working POC rather than brainstorming on visual model or document.

- Well designed solution makes simple scenarios easy. It should not prohibit complex things. Simple things should be simple and complex things should be possible.

- Trade-Offs between non functional requirements are inevitable. But we can try to achieve best balance between Trade-offs. ( Reliability Vs Extensibility, Power Vs Simplicity).

- Design should be scenario driven. Scenarios should lead to domain model.( Domain Driven Design).

- Adopting TDD, first create usage code of API exposed by each subsystem. API exposed by each layer should be usable in best possible way( less dependencies, Self contained catering a complete activity, easy to learn etc).

- Use minimum number of concepts while designing.

- Identify which classes should be generic/ templatised and which classes should be specific. Over generalization might provide extensibility but also result in issues related to: type safety, performance issues, understandability etc.

- Don't concentrate on specific extensibility( What if system might be used in a specific different way ?). Rather concentrate on loosely coupled , self contained components. It's easy to identify what might vary ( in the problem domain space) in future ( couple of years). Separate and encapsulate what varies and allow plugging in a new component for that varying behavior.

- Don't unnecessarily increase class hierarchy depth. Clearly Identify which requires a new class, which can be an attribute/member of a class........

- The mismatches between Relaional Model( database tables) and object model ( OO) should be manageable . Design should retain benefits of both models and resolve mismatches between both models

- If you don't want to be constrained in expressing domain model irrespective of the fact that it needs to be synced with relational model( database ) , then it's better to use patterns like DTO( Data Transfer Objects) / BO( Business Objects). These BO's need to be mapped with domain objects using frameworks like Automapper.

- Maintain constant feedback loop and let design evolve.

I am presenting AGILE methodology with my understanding.
:-).

Framework Patterns



Framework Patterns

Framework features

  • Framework approach of solving recursive problems in software is called “Old Code Calls New Code”. 
  • Framework has two important features 1) Kernel of framework 2) Hot spots.
  • Kernel of framework is immutable. The features of kernel cannot be altered and are called frozen spots of framework.
  • Hot spots in a framework are points of flexibility of a framework. They can be abstract classes that have no implementation and must be customized in order to be instantiated.

  •  Actually Hotspot may take the form of a) Hook Method b) Class c) Application.
  • Once framework is instantiated, frameworks kernel calls the hot spots (customized classes or methods) using the call-back mechanism.

  • Hotspots are the extensible points. Using hotspots, framework implements the design principle “Encapsulate what varies”.

Types of Frameworks

  1. White-box frameworks
  2. Black-box frameworks
  3. Backbone frameworks

White-Box Frameworks

Important patterns that help to build White-Box Frameworks (Skeleton applications)

1.       Template method pattern

  • Template method pattern defines the high level algorithm and allows sub classes to provide the implementation for one or more steps. 
  • It defines the skeleton of an algorithm, some steps will be deferred.
  • Template method pattern lets sub classes redefine certain steps of an algorithm without changing high level structure of solution algorithm.
  • The abstract class contains the template method.
  • The Template method makes use of primiteOperations to implement high level policy/algorithm.
  • Template method (high level logic) is decopuled from actual implementation of primitive operations.

MFC Message and Command Routing is a white-box framework.

  • Every Windows-based program needs a message pump to handle windows messages generated by user actions and system itself. 
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0)) 
        {
             TranslateMessage(&msg);
             DispatchMessage(&msg);  // send to window proc
        }
  • But a realistic message loop will not be as simple as that, since there are most common scenarios like a) Handling messages of modeless dialogs b) Handling accelerators etc.
  • MFC framework does this by itself; the message loop is encapsulated in CWinApp::Run
  • CWinApp::Run is the template method and it uses primitive operations like :- OnIdle, PumpMessage, PreTranslateMessage, DispatchMessage etc.
  • If required we can customize PreTranslateMessage.
  • When DispatchMessage is called, internally AfxWndProc gets invoked, which calls CWnd WindowProc, and WinowProc looks into the MESSAGE MAP Table and invokes callback message handlers implemented by developer.

  •  So the message handler functions (hot spots or extensible points) are the primitive operations that the High level message routing algorithm uses by call-back mechanism.

Black-Box Frameworks

  • The extensible components or hotspots will be external binary components.
  • But the extensible components should have a well defined interface.These extensible external components will be integrated into the framework.
  • Framework developers first define the interface of the hotspot. And developers who want to instantiate the framework write pluggable components implementing those interface(Contract). Then these custom pluggable components will be integrated with the framework.
  • In black-box frameworks we will have concrete and ready to use classes and services.
  • In black-box frameworks, components hide their internal implementation.
  • Black box frameworks will be configured (details of plug-ins or hotspots) to be instantiated.

Important patterns that help to build Black-Box Frameworks

1.       Strategy pattern (with Plug-and-Play mechanism)

  • Strategy pattern defines a family of algorithms, encapsulates each one and make them interchangeable.
  • Strategy pattern lets the algorithm vary independently from  clients that use it.
  • Strategy pattern allows "Plug-And-Play"-ing.
  •  The Context maintains the reference to a strategy object. It will be configured with the name of Concrete strategy class. And that concrete strategy will be loaded at compile-time.
  • The appropriate strategy(when a dll exporting Strategy interface is registered with Context) can be loaded dynamically.
Examples of Black-Box Frameworks

ADO.NET Data Providers

The ADO.NET Data Provider model provides a common managed interface in the .NET Framework for connecting to and interacting with a data store.  Third-party vendors provide the assemblies/binaries that expose that standard interface. Application using ADO.NET will be configured with the provider assembly details and appropriate plug-in will be loaded.

WinLogon , GINA and Network provide

  • Winlogon, the GINA, and network providers are the parts of the interactive logon model.
  • Interactive logon process is entirely controlled by Winlogon, but uses customizable GINA dll( for displaying custom dialogs and handling user interactions).
  • Winlogon sends secure attention sequence (SAS) events to GINA, so that appropriate UI is displayed.
  • Winlogon actually calls methods exposed by GINA like WlxNegotiate, WlxInitialize, WlxLoggedOutSAS, WlxLoggedOnSAS, WlxSasNotify etc corresponding to SAS event Winlogon encounters allowing third party GINA to provide custom UI and add additional steps in interactive logon process.
  • Winlogon also uses the network providers plug-ins. Following a successful logon, Winlogon calls network providers so they can collect credentials and authenticate the user for their network
  • This is a quite good example of Black-box framework, where the contract between framework kernel(Winlogon) and hotspots(GINA, Network providers) is well defined. Once third-party GINA is registered with Winlogon, Winlogon loads the plug-in and uses it for successful completion of interactive logon.
 

Design for Testability in .NET Frameworks


Design for Testability in .NET Frameworks


ASP.NET WEB Forms framework not developed with Testability in mind
  • One of the main intent of ASP.NET was to allow the developer focus on Business logic and abstracts the typical client side web elements like HTML, JavaScript and CSS.

  • Server controls allow developer to quickly and effectively arrange views. 
  • ASP.NET uses object-oriented model and event-oriented model. Page framework creates an object model based on the server control tags in the page and also fires a series of events and the handlers in code behind files gets executed.



  • By this some sort of separation of concerns is accomplished by separating UI rendering and event handling code(Code Behind Model and Server Controls).
  • Page framework renders the Controls object model into HTML tags with CSS formatting and Javascript code.
  • But if we see the dependencies on System.Web.UI.Page class, we can figure out that code-behind code is tightly coupled with ASP.NET runtime and to unit test a method in “code behind” we might require ASP.NET runtime. Mocking runtime is not allowed too. So unit testing methods in “code behind” is pretty hard. We might end-up doing integration testing even to get feedback about small changes which we make in the code behind.



  • Any code placed in a code-behind class has direct access to the HTTP context and can read and write cookies, posted data, query string parameters, session state, HTTP headers, and so forth. 

  • Code-behind classes during HTTP GET requests, setup the page to display and for HTTP POST requests, orchestrates the back-end process workflow, receives response from back-end and prepare the next view for the user.

  •  If the code behind has significant level of complexity with workflow to be orchestrated, the only way to validate the code is through integration testing(We need to trigger the UI).

  • ASP.NET Web Forms was successful in making the Web application behave very similar to desktop applications with concepts like Postback, ViewState, AJAX etc.But doesn't have proper separation of concerns to enhance testability.

ASP.NET MVC framework and Testability


  • When software is broken down into small parts and each part has a well-defined single responsibility and if each part is cohesive and loosely coupled, testability improves.

  •  If its easier to write unit tests for any part of the software, then development or maintenance  becomes faster and cheaper. 

  • MVC was designed from the ground up to be testable. Design choices were made to allow developers to create testable applications.
  • MVC Framework implements the MVC pattern, basically considered as an UI pattern. Major components being a) Model b) View c) Controller.

  •  The Controller which contains the logic related to flow of the application. UI code resides in View. Business logic (related to Business activities and processes) resides in the Model(Model in turn can consume back-end services or other BLL assemblies). This separation of concern improves testability and maintainability.

  • A Controller can be tested same as a simple POCO (Plain Old CLR Object). And Model classes are in fact POCO objects.

  • ASP.NET MVC Framework has most of its functionality as plug-gable and by that providing orthogonality to the framework. Developer can swap the default Controller factory with a custom controller factory(for dependency injection etc), developer even can easily replace (with mocks for testing) static helper classes like HttpContext and HttpRequest if required. These static helper classes are very well abstracted from the developer, in most cases we might not need to create instances of static helper classes.
  • The UI rendering engine (Razor) and the Routing Engine (that parses the URL and invokes the Handler) are not tied with MVC framework. They can be used in any .NET applications.
  • One of the main design principle of MVC being "Convention over Configuration". The user customized extensible parts of the framework(Controller, Views, Models etc) are automatically picked up by the framework based on their naming conventions and location inside the project structure. They need not be configured. But rules such as format of the URL must be configured so that Routing engine can extract data, name of the handler that it needs to invoke etc.


Entity Framework and Testability

  • In most of the applications, the Business Objects/Domain Objects Model doesn't will not be in synch with Data base schema (Logical Model of database).

    In most of the applications, the Business Objects/Domain Objects Model doesn't represent the Data base schema (Logical Model of database).

    Main driving force for Database schema is avoiding redundancy of data by normalization. A normalized database enhances the performance of data access and also ensures integrity and consistency of data.

    Main objective of Business Objectives/Domain Objectives is to allow re-usability, maintainability , easy extensibility of application logic by deriving Object Model from real world tangible objects in the problem domain. (Considering a Business Software Application is to automate an existing manual process).

    Data members in Business Objects  will not be normalized and data will be duplicated in different Domain Objects/Business objects.

    There is always a chance that data in one database table distributed in multiple in-memory Business Objects/Domain Objects.

    Data in a Domain Object/Business Object might also be split into multiple tables.

  • Entity frameworks major objective is to bridge the gap between the Business Objects( Conceptual data model) and Database Schema(Logical Model).
  •  EF abstracts the Logical database schema from the developer, so that developer need not write boiler plate code to access database and map the data retrieved into the BOs or DOs.
  •  Core of EF is Models. An Entity Framework Data Model contains 1) Conceptual model 2) Mapping Model 3) Logical Model.
  • Logical model(Schema definition of database) is hidden from the programmer, and Entities defined in the conceptual model will be used for database access and management.
  • Once the Conceptual Model, Mapping Model and Logical Model are defined, programmer need not retrieve the data in the same structure how data is stored in the database and feed them into Business Objects or Domain Objects. 
Testability Of EF
  • The big disadvantage of EF is rigid architecture, where it’s very difficult to mock some components of the framework.
  • In the database first approach, the default code generated by the code generation tools from the model contains ObjectContext class(which takes care of pulling data in and out of the database. It also keeps track of all changes during a business transaction. And the Entitiy classes that are generated are derived from EntityObject.
  • In the code first approach, the important classes are DbContext(wrapper around ObjectContext) and DbSet.DbSet represents an entity set. We will have one DbSet for each type in business /domain model. That entity can be an aggregate root of the domain. 

  •  ObjectContext, DbContext, DbSet, EntityObject being concrete classes, it’s difficult to mock them. 
  •  The other major disadvantage is the upper layers(BLL or UI) are aware of EF. It would be difficult to swap EF with other ORM in data access layer. 

  • So to make the code testable and to make the upper layers unaware of EF being used, EF code should be wrapped and to upper layers only interfaces to access the domain objects should be exposed.

  • ObjectContext/DbContext are by themselves implementation of UnitOfWork pattern. DbSet, Entityobject are by themselves implementation of Repository pattern. But since they are concrete classes, they are tied to EF. 

  • If we want to replace EF DbContext with some other data store context : ActiveDirectoryContext etc, it would be difficult to switch.
  • The solution would be to wrap ObjectContext/DbContext (EF specific Unit Of Work) in a generic UnitOfWork. Wrap the ObjectSet/DbSet (EF repositories) in generic Repository. Make the Domain Objects Persitent ignorant by allowing them to be just POCO Objects. 
  • T4 code generation templates to generate Repository & UnitOfWork patterns and testable POCO entity objects can be found