Rajnish Noonia

Tag: Architecture

  • From Staff Engineer to Engineering Director: What Actually Changes

    Many years as a lead architect building financial services platforms, delivering for large institutions with distributed teams across several countries and time zones. Hard integrations, architectures that had outgrown their original shape, problems where the right answer wasn’t technically obvious.

    Moving into an engineering director role, the first surprise is that last part describes the org problems too.

    The architecture parallel

    Take a document comparison (blacklining) platform. It tracked changes across large volumes of legal and financial documents: master agreements, contract amendments, standards documents. Per-client deployed. Each client ran their own instance. The core logic was identical across all of them, but nothing was shared. Every update meant coordinating across separate environments. Clients had diverged slightly from each other. Operational overhead scaled with the number of clients, not the volume of work.

    Before — per-client deployment: each client runs a full separate stack, updates and versions drift independently
    Client A Gateway Identity Compare Orchestrator Converter Logging v1.1 · own server Client B Gateway Identity Compare Orchestrator Converter Logging v1.3 · config drifted Client C Gateway Identity Compare Orchestrator Converter Logging v1.0 · update backlog ↔ ↔ isolated isolated

    The redesign moved it to a shared serverless SaaS platform. Two core services, independently deployable. A comparison service accepts two HTML documents and returns <ins>/<del> markup, with parallel processing and long-running execution for very large legal documents. A document orchestrator manages the multi-stage pipeline: fetching and caching source documents, dispatching comparison pairs via a message queue, receiving results via callback, and handing off to downstream consumers. A conversion service handles upstream document conversion. Centralised logging and metrics cover observability; an identity provider handles auth and an API gateway handles routing. Infrastructure is defined as code, so identical configuration is deployed to every environment with zero manual provisioning. CI/CD uses zero-downtime deployments. The platform scales out under queue pressure and drops to zero at idle.

    After — shared SaaS: one platform, multiple environments reproduced identically via infrastructure as code
    CONSUMERS Client A Client B Client C Support UI API Gateway routing · rate limiting · TLS Identity / auth Comparison Service <ins>/<del> comparison parallel · long-running serverless functions Orchestrator enrichment pipeline queue orchestration progress monitoring Converter document → HTML full fidelity serverless functions Observability structured logging metrics & tracing per-service views Queue Callback Cloud storage queues · blobs · tables Document store document source Infrastructure as code · CI/CD Dev → Test → Prod · identical config · zero-downtime deploys · scale to zero auto-scaling
    Architecture in motion — client traffic converges to a shared platform; services scale out on demand

    B E F O R EA F T E RClient AClient BClient CAPI GatewayCompareOrchestratorConverterIdentityObservabilitySaaS PlatformPer-client deploys → shared SaaS · scales out on demand, to zero at idle · identical environments via IaC

    It wasn’t designed just to solve the immediate problem. It was designed so the next engineer on the next document-heavy async workflow could follow the same pattern: queue topology, service boundaries, infrastructure module structure, callback model between services, poison queue and retry handling. When the team needed a similar capability for a different document type later, the shape was already there.

    Good org design works the same way. Build the operating structure once, make it followable, and the next person in a similar situation doesn’t reinvent from scratch. The difference is verification. In software you run tests and find out quickly. In an engineering organisation, feedback takes quarters and it’s noisy.

    What changes when the unit of output shifts

    As a lead architect, the value you deliver is legible. You write the design, the team builds from it, you can point to the system and attribute specific decisions. The feedback loop is tight. Did the queue-backed processing hold up under the document volume we projected? Did the infrastructure module composition cause problems when we added the conversion service? You find out quickly.

    As a director, the best work you do is nearly invisible. A team that ships consistently, that surfaces real problems early, that makes sound architectural decisions without needing sign-off on every one: that’s the output. It doesn’t show up in any particular artefact. It shows up as the absence of the problems that would otherwise be present.

    That makes the feedback loop much harder to close. In architecture, you know whether your comparison service handles very large documents within timeout bounds. In leadership, the equivalent signal arrives slowly and with a lot of noise: does this team have the right capability mix for what’s coming in the next two quarters? The technical habits that help most here are the ones about holding problems at the right level of abstraction. Not diving into implementation detail when the real question is about interface design. Not fixating on a specific solution when the actual problem is a constraint you haven’t identified yet. Lead architecture work builds that instinct through iteration. It applies directly when the system is a team and the constraints are skills, relationships, and delivery risk.

    Technical credibility has a different role

    Staying technically credible in a director role is less about making good technical decisions yourself and more about maintaining the environment where other people make them well.

    That means being precise enough in design discussions that engineers can’t paper over complexity with confident language. It means understanding the failure modes of the patterns the team uses. Queue-backed serverless architectures have specific operational characteristics around poison messages, scaling lag, and storage cost that matter in production and need to be understood, not just referenced. It means being able to read an infrastructure-as-code plan and understand what’s actually being proposed, not just whether the CI checks pass.

    What it doesn’t mean, and this is the trap, is using that credibility to make the calls yourself. The job is to raise the quality of the decisions, not to be the source of them. A director who consistently overrides architectural choices in design reviews has optimised for short-term correctness at the cost of long-term ownership. A few months of that and engineers stop proposing designs and start waiting for instructions. The technical quality stays roughly the same. The team’s ability to function without you degrades steadily.

    In practice: less “have you considered X” and more “what’s driving the tradeoff between X and Y?” The first substitutes your judgment. The second develops theirs.

    Hiring is the hardest architectural decision

    The hardest architecture decisions aren’t about technology choices. They’re about what to build versus buy, what to build now versus defer, what to design for extensibility versus what to deliberately dead-end because the requirements aren’t stable enough yet. The cost of a wrong call is proportional to how deeply it’s been built in and how long it’s been there.

    The same logic applies to team composition. A team’s capability is the result of who is on it, and hiring decisions compound over years. A well-placed senior hire in the right gap can unblock six months of stuck delivery. Slow backfilling, or consistently hiring for available rather than needed, degrades what the team can build in ways that don’t show up clearly until the gap is already expensive to close.

    Working across distributed teams in several countries adds a layer of complexity the org chart doesn’t capture. The skills market is genuinely different in each location. The availability of engineers with specific domain backgrounds varies significantly. The timing of a hire matters relative to which team is carrying which delivery risk. You can’t treat it as one global hiring problem with uniform parameters. Model it the way you’d model a distributed system with different latency and throughput characteristics in each region: understand the local constraints, plan accordingly, and don’t assume what works in one location translates to another.

    The actual transition

    The shift isn’t about personality. It’s about what you’re optimising for. As a lead architect, you’re optimising for the quality of what gets built. As a director, you’re optimising for the quality of the team that builds things: what it can do now, its capability six months from now, its risk profile, how much delivery depends on a small number of individuals, whether the architectural patterns it’s following will hold under changing requirements.

    Both need technical depth. Neither requires abandoning it. The depth operates at a different resolution: wider and shallower across the whole surface, deliberately deep in the areas that most affect the team’s next quarter of work. The instincts from years of architecture work, finding where complexity hides, separating fundamental constraints from implementation choices, remain the most useful tools in the kit. Same tools, different system.

  • Building a TypeScript-First Frontend SDK: An Architectural Journey

    Over the past few years I have spent much of my time on one recurring problem: how do you let many teams build many data-intensive web applications without each of them reinventing the same foundations? This post walks through the architectural journey of designing a TypeScript-first frontend SDK to answer that question. It focuses on the patterns and trade-offs rather than any particular implementation, because the ideas travel well beyond the project that prompted them.

    Application layer Individual applications built on the platform Data grid apps Dashboards Workflow tools Admin tools Others… Framework layer Native React and Angular — thin bindings over the core Angular bindings Components · Directives · DI bridge React bindings Components · Hooks · DI bridge Core Framework-agnostic TypeScript — no UI framework dependency MVVMViewModel · State IoC / DIContainer · Discovery Data gridConfig · Streaming FormsRules · Validation ShellConfig-driven LayoutPanels · Persist ThemingTokens · Dark mode MessagingEvents · Notifications VisualisationCharts · Maps StreamingObservables ObservabilityLogging · Tracing · APM SecurityAuth · Permissions AI-ready contextContext files · Agent rules Scaffolding CLI + delivery pipeline CI/CD · Containers · AWS · dev / test / prod environments
    A layered SDK: framework-agnostic core, thin React/Angular bindings, and applications on top

    The Starting Point: Why a Component Library Is Not Enough

    The usual answer to “we need consistency across teams” is a component library: styled buttons, inputs and grids published as a package. In my experience that solves perhaps a fifth of the real problem. It says nothing about where state lives, how view logic is tested without rendering, how the same feature behaves identically in two UI frameworks, how dependent form fields validate each other, or how any of it stays coherent across years of changing teams.

    So the goal shifted from “shared components” to “shared architecture”: a TypeScript-first, framework-agnostic SDK in which React and Angular are equal, native rendering targets. The choice of view framework becomes a team preference, not an architectural fork.

    Principle 1: MVVM Keeps the View Thin

    The most important decision was to adopt Model–View–ViewModel as the backbone. The view is a template that binds to properties and commands. The ViewModel is a plain TypeScript class that owns state and behaviour. The model is data and services. Nothing else is allowed to blur those lines.

    Three benefits follow. Testability: a ViewModel has no JSX and no decorators, so business logic is tested as ordinary unit tests instead of by mounting components and poking the DOM. Reuse across frameworks: the same ViewModel drives a React view and an Angular view, so behaviour is written once. Clarity: engineers always know where logic belongs, which removes a whole category of code-review debate.

    Principle 2: Dependency Injection Owned by the Core

    MVVM only works well when ViewModels can ask for what they need without knowing where it comes from. Neither framework’s native mechanism fits: Angular’s injector only exists in Angular, and React context is not really DI. The answer was an IoC container that lives in the core, independent of any UI framework, with thin bridges into each one – a hook-based resolver for React and an injector bridge for Angular.

    Services are registered against interfaces, and can be discovered by capability rather than concrete type. This is where SOLID stops being a slide and becomes the path of least resistance: new behaviour arrives as a new registration, not an edit to existing classes, and every dependency can be swapped for a test double.

    Principle 3: Layers With Enforced Boundaries

    The SDK is organised as a monorepo with three layers:

    • Core: pure TypeScript – MVVM primitives, the container, state, messaging, streaming, configuration, theming tokens and platform services. No UI framework dependency.
    • Framework bindings: thin React and Angular packages that render the core’s concepts natively and bridge the container into each framework.
    • Applications: products built on a shared, configuration-driven shell, deployable to the browser or to desktop containers.

    Build-time boundary rules stop applications from reaching into the core directly and reject circular dependencies. Architecture that is only documented erodes; architecture that fails the build stays intact.

    Principle 4: Solve Cross-Cutting Concerns Once

    Most of the value of a platform is in the unglamorous capabilities that every application needs and no team wants to build. Rather than leave them to each project, the SDK provides them as shared services:

    • Configuration-driven shell and layout: navigation, panels and workspaces declared in configuration, with dockable panels whose arrangement is persisted per user.
    • State persistence: any screen can opt in to having column widths, filters, sort order and layout restored on reload.
    • Data grid abstraction: grids configured declaratively, with streaming updates delivered through observables, so teams write configuration and a ViewModel rather than grid plumbing.
    • Forms with a rule engine: field dependencies, visibility and validation expressed as rules; client and server validation surface through one pipeline.
    • Design tokens: semantic colours, spacing and typography exposed as typed constants and CSS variables, with dark mode as a first-class theme.
    • Observability and security: structured logging, tracing and application performance monitoring wired in by default, alongside authentication and permission handling.

    Principle 5: Start Every Project From Working, Not Blank

    A scaffolding CLI turns the SDK into a starting point rather than a set of instructions. A few commands produce an application that already has the shell, theming, authentication, observability, CI/CD pipelines, container configuration and cloud deployment templates for AWS across dev, test and production environments. The decisions that usually consume a project’s first sprint are already made, and every project starts in the same shape – which makes moving between them much easier for engineers.

    Principle 6: Design for AI-Assisted Development

    A newer lesson: an SDK now has two audiences, human developers and AI coding agents. Each package carries a concise context file describing its patterns, naming conventions and rules, and a routing structure points an agent at only the context relevant to its task. Generated projects inherit these files automatically.

    Treating that context as a maintained deliverable – updated alongside code and checked in CI – keeps agents inside the architecture instead of inventing their own. The result is AI assistance that accelerates teams without quietly eroding standards.

    Principle 7: Governance That Scales

    • Enforced module boundaries at build time
    • Semantic versioning with deprecation windows, so nothing disappears without warning
    • Living documentation: component catalogues and visual regression tests in the pipeline
    • Context files as a contract for both humans and agents

    What I Took Away

    The measurable outcome was that applications which once took months could be delivered in weeks, with a consistent look, feel and behaviour. But the more lasting lessons were architectural:

    • Separate behaviour from rendering early; it is very hard to retrofit.
    • Own your dependency injection in the core if you want framework independence.
    • Encode rules in the build, not in wiki pages.
    • Invest in the boring cross-cutting services – that is where teams lose the most time.
    • Treat AI context as part of the product, not an afterthought.

    A good platform is measured by how rarely the teams building on it need to think about it.

  • Behavioural Design Patterns

    Behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.

    Behavioural Patterns

    • Mediator:- Defines simplified communication between classes.
    • Memento:-Capture and restore an object’s internal state.
    • Interpreter: – A way to include language elements in a program.
    • Iterator:-Sequentially access the elements of a collection.
    • Chain of Resp: – A way of passing a request between a chain of objects.
    • Command:-Encapsulate a command request as an object.
    • State:-Alter an object’s behavior when its state changes.
    • Strategy:-Encapsulates an algorithm inside a class.
    • Observer: – A way of notifying change to a number of classes.
    • Template Method:- Defer the exact steps of an algorithm to a subclass.
    • Visitor:- Defines a new operation to a class without change.

    Many a times in projects communication between components are complex. Due to this the logic between the components becomes very complex. Mediator pattern helps the objects to communicate in a disassociated manner, which leads to minimizing complexity.Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
    Example : The classes and/or objects participating in this pattern are:

    • Mediator (IChatroom)
      • defines an interface for communicating with Colleague objects
    • ConcreteMediator (Chatroom)
      • implements cooperative behavior by coordinating Colleague objects
      • knows and maintains its colleagues
    • Colleague classes (Participant)
      • each Colleague class knows its Mediator object
      • each colleague communicates with its mediator whenever it would have otherwise communicated with another colleague
    interface IChatroom
    {
        void Send(string message, Colleague participant);
    
    }
    class Chatroom : IChatroom
    {
        Colleague colleague1;
        Colleague colleague2;
    
        public Colleague Colleague1
        {
            set { colleague1 = value; }
        }
    
        public Colleague Colleague2
        {
            set { colleague2 = value; }
        }
    
        public void Send(string message, Colleague colleague)
        {
            if (colleague == colleague1)
            {
                colleague2.Notify(message);
            }
            else
            {
                colleague1.Notify(message);
            }
        }
    }
    abstract class Participant
    {
        protected IChatroom mediator;
        string name;
        // Constructor
        public Participant(string Name, IChatroom mediator)
        {
          this.mediator = mediator;
          this.name = Name;
        }
        public string Name
        {
            get { return this.name; }
        }
      }
    
    class Colleague:Participant
    {
    
        public Colleague(string Name, IChatroom mediator) : base(Name, mediator) { }
    
        public void Send(string message)
        {
          mediator.Send(message, this);
        }
    
        public void Notify(string message)
        {
          Console.WriteLine( this.Name + " gets message: "  + message);
        }
    
    }
    //Application
    Chatroom room = new Chatroom();
    Colleague c1 = new Colleague("Rajneesh Noonia", room);
    Colleague c2 = new Colleague("Robert", room);
    room.Colleague1 = c1;
    room.Colleague2 = c2;
    c1.Send("How are you?");
    c2.Send("Fine, thanks");

    Memento pattern is the way to capture objects internal state with out violating encapsulation. Memento pattern helps us to store a snapshot which can be reverted at any moment of time by the object. Let’s understand what it means in practical sense. Consider ‘Memento practical example’, it shows a customer screen. Let’s say if the user starts editing a customer record and he makes some changes. Later he feels that he has done something wrong and he wants to revert back to the original data. This is where memento comes in to play. It will help us store a copy of data and in case the user presses cancel the object restores to its original state.The memento pattern is used by two objects: the originator and a caretaker. The originator is some object that has an internal state. The caretaker is going to do something to the originator, but wants to be able to undo the change. The caretaker first asks the originator for a memento object. Then it does whatever operation (or sequence of operations) it was going to do. To roll back to the state before the operations, it returns the memento object to the originator. The memento object itself is an opaque object (one which the caretaker cannot, or should not, change). When using this pattern, care should be taken if the originator may change other objects or resources – the memento pattern operates on a single object.
    Example :

    // The 'Originator' class
    class Originator
    {
        private string _state;
        // Property
        public string State
        {
            get { return _state; }
            set
            {
                _state = value;
                Console.WriteLine("State = " + _state);
            }
        }
    
        // Creates memento
        public Memento CreateMemento()
        {
            return (new Memento(_state));
        }
        // Restores original state
        public void SetMemento(Memento memento)
        {
            Console.WriteLine("Restoring state...");
            State = memento.State;
        }
    }
    
    // The 'Memento' class
    class Memento
    {
        private string _state;
        // Constructor
        public Memento(string state)
        {
            this._state = state;
        }
        // Gets or sets state
        public string State
        {
            get { return _state; }
        }
    }
    
    // The 'Caretaker' class
    class Caretaker
    {
        private Memento _memento;
        // Gets or sets memento
        public Memento Memento
        {
            set { _memento = value; }
            get { return _memento; }
        }
    }
    //Application
    
    Originator o = new Originator();
    o.State = "On";
    // Store internal state
    Caretaker c = new Caretaker();
    c.Memento = o.CreateMemento();
    // Continue changing originator
    o.State = "Off";
    // Restore saved state
    o.SetMemento(c.Memento);

    Interpreter pattern allows us to interpret grammar in to code solutions. Ok, what does that mean ?. Grammars are mapped to classes to arrive to a solution. For instance 7 – 2 can be mapped to ‘Minus’ class. In one line interpreter pattern gives us the solution of how to write an interpreter which can read a grammar and execute the same in the code. The interpreter pattern specifies how to evaluate sentences in a language. The basic idea is to have a class for each symbol (terminal or nonterminal) in a specialized computer language. The syntax tree of a sentence in the language is an instance of the composite pattern and is used to evaluate (interpret) the sentence.
    Example :

    interface IExpression
    {
        int Interpret(Dictionary variables);
    }
    
    class Number : IExpression
    {
        public int number;
        public Number(int number) { this.number = number; }
        public int Interpret(Dictionary<string, int> variables) { return number; }
    }
    
    abstract class BasicOperation : IExpression
    {
        IExpression leftOperator, rightOperator;
    
        protected BasicOperation() { }
    
        public BasicOperation(IExpression left, IExpression right)
        {
            leftOperator = left;
            rightOperator = right;
        }
    
        public int Interpret(Dictionary<string, int> variables)
        {
            return Execute(leftOperator.Interpret(variables), rightOperator.Interpret(variables));
        }
    
        abstract protected int Execute(int left, int right);
    }
    
    class Plus : BasicOperation
    {
        public Plus(IExpression left, IExpression right) : base(left, right) { }
    
        protected override int Execute(int left, int right)
        {
            return left + right;
        }
    }
    
    class Minus : BasicOperation
    {
        public Minus(IExpression left, IExpression right) : base(left, right) { }
    
        protected override int Execute(int left, int right)
        {
            return left - right;
        }
    }
    
    class Variable : IExpression
    {
        private string name;
    
        public Variable(string name) { this.name = name; }
    
        public int Interpret(Dictionary<string, int> variables)
        {
            return variables[name];
        }
    }
    
    class Evaluator
    {
        private IExpression syntaxTree;
    
        public Evaluator(string expression)
        {
            Stack<IExpression> stack = new Stack<IExpression>();
            foreach (string token in expression.Split(' '))
            {
                if (token.Equals("+"))
                    stack.Push(new Plus(stack.Pop(), stack.Pop()));
                else if (token.Equals("-"))
                    stack.Push(new Minus(stack.Pop(), stack.Pop()));
                else
                    stack.Push(new Variable(token));
            }
            syntaxTree = stack.Pop();
        }
    
        public int Evaluate(Dictionary<string, int> context)
        {
            return syntaxTree.Interpret(context);
        }
    }
    
    //Application
    
    Evaluator evaluator = new Evaluator("w x z - +");
    Dictionary<string, int> values = new Dictionary<string,int>();
    values.Add("w", 5);
    values.Add("x", 8);
    values.Add("z", 15);
    Console.WriteLine(evaluator.Evaluate(values));

    Iterator pattern allows sequential access of elements with out exposing the inside code. Let’s understand what it means. Let’s say you have a collection of records which you want to browse sequentially and also maintain the current place which recordset is browsed, then the answer is iterator pattern. It’s the most common and unknowingly used pattern. Whenever you use a ‘foreach’ (It allows us to loop through a collection sequentially) loop you are already using iterator pattern to some extent.
    Example :

    public class Employee{   
        private int m_nID;
        private string m_strName;
        public Employee(int nID, string strName){
            m_nID = nID;
            m_strName = strName;
        }
        public int EmployeeID{get{return this.m_nID;}}
        public string EmployeeName{get{return this.m_strName;}}
    }
    public class EnumerateEmployee: IEnumerator
    {
        private int m_nPosition;
        private ArrayList m_ArrEmployee = new ArrayList();
        public EnumerateEmployee(){
            m_nPosition = -1;
            m_ArrEmployee.Add(new Employee(1,"Kamsa"));
            m_ArrEmployee.Add(new Employee(2,"Rama"));
            m_ArrEmployee.Add(new Employee(3,"Sita"));
            m_ArrEmployee.Add(new Employee(4,"Gopala"));
        }
        public bool MoveNext(){
            bool b_return = false;
            ++m_nPosition;
            if(m_nPosition < m_ArrEmployee.Count)
            b_return = true;
            return b_return;
        }
        public object Current {get{return m_ArrEmployee[m_nPosition];}}
        public void Reset(){m_nPosition = -1;}
    }
    
    //Application
    
    string strName;
    int nID;
    EmployeeList objEmpList = new EmployeeList();
    IEnumerator objEnumEmp = objEmpList.GetEnumerator();
    while(objEnumEmp.MoveNext())
    {
        Employee objEmployee = (Employee)objEnumEmp.Current; 
        nID = objEmployee.EmployeeID; strName = objEmployee.EmployeeName;
    }
    

    Chain of responsibility is used when we have series of processing which will be handled by a series of handler logic. There are situations when a request is handled by series of handlers. So the request is taken up by the first handler, he either can handle part of it or can not, once done he passes to the next handler down the chain. This goes on until the proper handler takes it up and completes the processing. Example :

    class Purchase
    {
        public int Number { get; set; }
        public double Amount { get; set; }
        public string Description { get; set; }
        public Purchase(int Number, double Amount, string Description)
        {
            this.Number = Number;
            this.Amount = Amount;
            this.Description = Description;
        }
    }
    
    abstract class Approver
    {
        protected Approver(Approver Successor)
        {
            this.Successor = Successor;
        }
        protected Approver Successor { get; private set; }
        public abstract void ProcessRequest(Purchase purchase);
    }
    
    //Various Approvers (request handlers)
    class Director : Approver
    {
        public Director(Approver Successor):base(Successor){}
        
        public override void ProcessRequest(Purchase purchase)
        {
            if (purchase.Amount < 10000.0)
            {
                Console.WriteLine("{0} approved request# {1}",this.GetType().Name, purchase.Number);
            }
            else if (Successor != null)
            {
                Successor.ProcessRequest(purchase);
            }
        }
    }
    
    class VicePresident : Approver
    {
        public VicePresident(Approver Successor) : base(Successor) { }
        public override void ProcessRequest(Purchase purchase)
        {
            if (purchase.Amount < 25000.0)
            {
                Console.WriteLine("{0} approved request# {1}",this.GetType().Name, purchase.Number);
            }
            else if (Successor != null)
            {
                Successor.ProcessRequest(purchase);
            }
        }
    }
    
    class President : Approver
    {
        public President(Approver Successor) : base(Successor) { }
        public override void ProcessRequest(Purchase purchase)
        {
            if (purchase.Amount < 100000.0)
            {
                Console.WriteLine("{0} approved request# {1}",this.GetType().Name, purchase.Number);
            }
            else
            {
                Console.WriteLine("Request# {0} requires an executive meeting!",purchase.Number);
            }
        }
    }
    
    //Application
    // Setup Chain of Responsibility
    
    Approver director = new Director(null);
    Approver vicePresident = new VicePresident(director);
    Approver president = new President(vicePresident);
    
    // Generate and process purchase requests
    Purchase p = new Purchase(2034, 350.00, "Assets");
    director.ProcessRequest(p);
    
    p = new Purchase(2035, 32590.10, "Project X");
    director.ProcessRequest(p);
    
    p = new Purchase(2036, 122100.00, "Project Y");
    director.ProcessRequest(p);
    

    Command pattern allows a request to exist as an object. The command pattern is a design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. This information includes the method name, the object that owns the method and values for the method parameters.

    Three terms always associated with the command pattern are client, invoker and receiver. The client instantiates the command object and provides the information required to call the method at a later time. The invoker decides when the method should be called. The receiver is an instance of the class that contains the method’s code.

    Using command objects makes it easier to construct general components that need to delegate, sequence or execute method calls at a time of their choosing without the need to know the owner of the method or the method parameters.
    Example :

    State pattern allows an object to change its behavior depending on the current values of the object. Consider the ‘State pattern example’. It’s an example of a bulb operation. If the state of the bulb is off and you press the switch the bulb will turn off. If the state of bulb is on and you press the switch the bulb will be off. So in short depending on the state the behavior changes. Example :

    Strategy pattern are algorithms inside a class which can be interchanged depending on the class used. This pattern is useful when you want to decide on runtime which algorithm to be used.
    Example :

    Observer pattern helps us to communicate between parent class and its associated or dependent classes. There are two important concepts in observer pattern ‘Subject’ and ‘Observers’. The subject sends notifications while observers receive notifications if they are registered with the subject. Example :

    In template pattern we have an abstract class which acts as a skeleton for its inherited classes. The inherited classes get the shared functionality. The inherited classes take the shared functionality and add enhancements to the existing functionality. In word or power point how we take templates and then prepare our own custom presentation using the base. Template classes works on the same fundamental.
    Example :

    Visitor pattern allows us to change the class structure with out changing the actual class. Its way of separating the logic and algorithm from the current data structure. Due to this you can add new logic to the current data structure with out altering the structure. Second you can alter the structure with out touching the logic. Example :

    *Visitor and strategy look very much similar as they deal with encapsulating complex logic from data. We can say visitor is more general form of strategy.

  • Structural Design Patterns

    Structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities.

    In this tutorial you will learn about Structural Patterns – Adapter, Bridge, Composite, Decorator, Facade, Flyweight and Proxy.

    Structural Patterns

    • Adapter:-Match interfaces of different classes.
    • Bridge:-Separates an object’s abstraction from its implementation.
    • Composite:-A tree structure of simple and composite objects.
    • Decorator:-Add responsibilities to objects dynamically.
    • Facade:-A single class that represents an entire subsystem.
    • Flyweight:-A fine-grained instance used for efficient sharing.
    • Proxy:-An object representing another object.

    Many times two classes are incompatible because of incompatible interfaces. Adapter pattern helps us to wrap a class around the existing class and make the classes compatible with each other. There are two way of implementing adapter pattern one is by using aggregation (this is termed as the object adapter pattern) and the other inheritance (this is termed as the class adapter pattern).

    Example :

    // Existing class.. this may be your legacy code or third party code
    class Adaptee
    {
        // validates the email
        public bool IsEmail(string email)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(email, @"email validation reg expression here");
        }
    }
    
    // Required standard implementing through interface
    interface ITarget
    {
        // Rough estimate required
        bool ValidateEmail(string email);
    }
    // Implementing the required standard via Adaptee
    class Adapter : Adaptee, ITarget
    {
        public bool ValidateEmail(string email)
        {
            return IsEmail(email);
        }
    }
    //Application
    
      // Showing the Adaptee in standalone mode
            Adaptee first = new Adaptee();
            bool valid = first.IsEmail("rajneeshnoonia@gmail.com"));
    
            // What the client really wants
           // Note that  Adaptee (3rd party or legacy code) is not used here,and Adapter is wraper for
           // Adaptee accessed via standard interface ITarget.If in future we found better adaptee we would not be require
          // to change client code.
            ITarget second = new Adapter();
           valid = second.ValidateEmail("rajneeshnoonia@gmail.com"));

    Bridge pattern helps to decouple abstraction from implementation. With this if the implementation changes it does not affect abstraction and vice versa. The switch is the abstraction and the electronic equipments are the implementations. The switch can be applied to any electronic equipment, so the switch is an abstract thinking while the equipments are implementations.

    interface IDraw
    {
        void DrawCircle(double x, double y, double radius);
    }
    
    class DrawGDI : IDraw
    {
        public void DrawCircle(double x, double y, double radius)
        {
           //Draw Circle using GDI API
        }
    }
    class DrawDirectX : IDraw
    {
        public void DrawCircle(double x, double y, double radius)
        {
            //Draw Circle using DirectX API
        }
    
    }
    
    interface Shape
    {
        void Draw();
    }
    class Circle:Shape
    {
        private double x, y, radius;
        private IDraw display;
        public Circle(double x, double y, double radius, IDraw display)
        {
            this.x = x;
            this.y = y;
            this.radius = radius;
            this.display = display;
        }
    
        public void Draw()
        {
            this.display.DrawCircle(this.x, this.y, this.radius);
        }
    }
    
    //Application
    List<Shape> shapes = new List<Shape>();
    shapes.Add(new Circle(10,10,20,new DrawGDI()));
    shapes.Add(new Circle(40,10,20,new DrawDirectX()));
    foreach (Shape shape in shapes)
    {
        shape.Draw();
    }

    Composite pattern allows treating different objects in a similar fashion. In order to treat objects in a uniformed manner we need to inherit them from a common interface.The Composite Design pattern allows a client object to treat both single components and collections of components identically. 

    Example :

    interface IGraphics
    {
        void Draw();
    }
    
    class Circle : IGraphics
    {
        public void Draw()
        {
            //Draw Circle
        }
    }
    
    class Composite : IGraphics
    {
        private List<IGraphics> childs = new List<IGraphics>();
        public Composite(IEnumerable<IGraphics> composite)
        {
            childs.AddRange(composite);
        }
        public void Draw()
        {
            //Draw composite graphics
            foreach (IGraphics child in this.childs)
            {
                child.Draw();
            }
        }
    }
    
    //Application
    //Build tree of objects
    Composite CGraphics1 = new Composite(new IGraphics[]{new Circle(),new Circle()});
    Composite CGraphics2 = new Composite(new IGraphics[]{CGraphics1,new Circle(),new Circle()});
    Composite CompositeGraphic = new Composite(new IGraphics[]{CGraphics2,new Circle()});
    CompositeGraphic.Draw();
     

    Decorator pattern is a design pattern that allows new/additional behaviour to be added to an existing object dynamically.
    The decorator pattern can be used to make it possible to extend (decorate) the functionality of a certain object at runtime, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new decorator class that wraps the original class.

    Decorator Patterns belong to the Structural Pattern category and it’s role is in providing a way of attaching new behavior to the object at run time. The object is unaware of the new behavior and this pattern is a good candidate for enhancing legacy applications. Decorator Pattern provides a way of adding functionality to an existing class without using inheritance.

    Example :

    Let us assume we are maintaining an application for a car manufacturing company. When the application was created, the company manufactured only one type of car – the normal car.

    interface ICar
    {
        string Description {get;}
        double Price{ get;}
     }
    class NormalCar:ICar
    {
        public string  Description
        {
            get { return "Normal Car"; }
        }
    
        public double  Price
        {
    	    get { return 2000f; }
        }
    }

    Over several years, the customers demanded that they be provided with different options to customize the car. The management decided to provide two different options. One to customize the paint based on the customer needs and the other an option to fit the car with a turbo charged engine.

    To enhance the application to support customizations, we could extend the Normal Car’s functionality by creating derived classes such as CustomPaintCar or TurboEngineCar. In future, if the management decides to provide more options, it would be practically impossible to create classes that can be used for different combinations.

    By using the Decorator pattern, we could combine different options at run time. First, we need to create a Decorator base class.

    abstract class CarDecorator:ICar
    {
        private ICar car;
        public CarDecorator(ICar car)
        {
            this.car=car;
        }
        public virtual string  Description
        {
    	    get { return this.car.Description; }
        }
    
        public virtual double  Price
        {
    	    get { return this.car.Price; }
        }
    }
    
    class CustomPaintCar :CarDecorator
    {
        public CustomPaintCar(ICar car):base(car){}
        public override string  Description
        {
    	    get
    	    {
    		     return base.Description + " with custom paint";
    	    }
        }
        public override double  Price
        {
    	    get
    	    {
    		     return base.Price + 1000f;
    	    }
        }
    }
    class TurboEngineCar :CarDecorator
    {
        public TurboEngineCar(ICar car):base(car){}
        public override string  Description
        {
    	    get
    	    {
    		     return base.Description + " with turbo engine";
    	    }
        }
        public override double  Price
        {
    	    get
    	    {
    		     return base.Price + 2000f;
    	    }
        }
    }
    //Application
    //Normal or basic car with
    ICar basicCar = new NormalCar();
    //exiting car = normal car + custom paint
    ICar exitingCar = new CustomPaintCar(new NormalCar());
    //amazing car = normal car + custom paint + turbo engine
    ICar amazingCar = new TurboEngineCar(new CustomPaintCar(new NormalCar()));

    Facade pattern sits on the top of group of subsystems and allows them to communicate in a unified manner.

    The classes and/or objects participating in this pattern are:

    Facade   (MortgageApplication)

    • knows which subsystem classes are responsible for a request.
    • delegates client requests to appropriate subsystem objects.

    Subsystem classes   (Bank, Credit, Loan)

    • implement subsystem functionality.
    • handle work assigned by the Facade object.
    • have no knowledge of the facade and keep no reference to it.

    Example :

      // The 'Subsystem ClassA' class
      class SubSystemOne
      {
        public void MethodOne()
        {
    
        }
      }
      // The 'Subsystem ClassB' class
      class SubSystemTwo
      {
        public void MethodTwo()
        {
    
        }
      }
      // The 'Subsystem ClassC' class
      class SubSystemThree
      {
        public void MethodThree()
        {
    
        }
      }
    
      // The 'Subsystem ClassD' class
      class SubSystemFour
      {
        public void MethodFour()
        {
    
        }
      }
      // The 'Facade' class
      class Facade
      {
        private SubSystemOne _one;
        private SubSystemTwo _two;
        private SubSystemThree _three;
        private SubSystemFour _four;
        public Facade()
        {
          _one = new SubSystemOne();
          _two = new SubSystemTwo();
          _three = new SubSystemThree();
          _four = new SubSystemFour();
        }
        public void MethodA()
        {
          _one.MethodOne();
          _two.MethodTwo();
          _four.MethodFour();
        }
        public void MethodB()
        {
          _two.MethodTwo();
          _three.MethodThree();
        }
      }
    
    //Application
    Facade facade = new Facade();
    facade.MethodA();
    facade.MethodB();

    Fly weight pattern is useful where we need to create many objects and all these objects share some kind of common data. Consider ‘Objects and common data’. We need to print visiting card for all employees in the organization. So we have two parts of data one is the variable data i.e. the employee name and the other is static data i.e. address. We can minimize memory by just keeping one copy of the static data and referencing the same data in all objects of variable data. So we create different copies of variable data, but reference the same copy of static data. With this we can optimally use the memory.

    Example : Support you have a project to create employee ID card.The variable data here will be employee name and employee ID where as the common or shared data here will be Company address.

    //abstract address
    public abstract class Address
    {
        public abstract string Address1 { get; set; }
    }
    //concreate address
    internal class CompanyAddress : Address
    {
        string address;
        public override string Address1
        {
            get { return address; }
            set { address = value; }
        }
    }
    //singleton pattern to have one instance of address
    public sealed partial class Application
    {
        public static Address CompAddress { get; private set; }
        static Application()
        {
            CompAddress = new CompanyAddress();
            CompAddress.Address1 = "Company Address";
        }
    
    }
    //abstract IDCard
    public abstract class IDCard
    {
        public string Name { get; set; }
        public int EmpCode { get; set; }
        public abstract Address CompanyAddress { get;}
    }
    
    //Concreate implementation of IDCard
    public class EmployeeIDCard : IDCard
    {
        public override Address CompanyAddress
        {
            get
            {
                return Application.CompAddress;
            }
        }
    }
    
    //Application
    List cards = new List();
    
    for (int empCode = 1; empCode <= 2000; empCode++)
    {
        cards.Add(new EmployeeIDCard { EmpCode=empCode,Name = String.Format("Emp{0} Name",empCode)});
    }

    Proxy pattern fundamentally is a class functioning as in interface which points towards the actual class which has data. This actual data can be a huge image or an object data which very large and can not be duplicated. So you can create multiple proxies and point towards the huge memory consuming object and perform operations. This avoids duplication of the object and thus saving memory. Proxies are references which points towards the actual object. The advantages of using proxy are security and avoiding duplicating objects which are of huge sizes. Rather than shipping the code we can ship the proxy, thus avoiding the need of installing the actual code at the client side. With only the proxy at the client end we ensure more security. Second point is when we have huge objects it can be very memory consuming to move to those large objects in a network or some other domain. So rather than moving those large objects we just move the proxy which leads to better performance.
    Example :
    A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.

    interface IImage
    {
        void Display();
    }
    
    class RealImage : IImage
    {
        public RealImage(string fileName)
        {
            FileName = fileName;
            LoadFromFile();
        }
    
        private void LoadFromFile()
        {
            Console.WriteLine("Loading " + FileName);
        }
    
        public String FileName { get; private set; }
    
        public void Display()
        {
            Console.WriteLine("Displaying " + FileName);
        }
    }
    
    class ProxyImage : IImage
    {
        public ProxyImage(string fileName)
        {
            FileName = fileName;
        }
    
        public String FileName { get; private set; }
    
        private IImage image;
    
        public void Display()
        {
            if (image == null)
                image = new RealImage(FileName);
            image.Display();
        }
    }
    //Application
    IImage image = new ProxyImage("HiRes_Image");
    for (int i = 0; i < 10; i++)
        image.Display();
    
  • Creational Design Patterns

    Creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.

    In this tutorial you will learn about Creational Design Patterns, Factory Method, Abstract Factory, Builder, Prototype and Singleton.

    Creational Patterns (all about creation of objects)

    • Factory Method: – Creates an instance of several derived classes.
    • Abstract Factory: – Creates an instance of several families of classes.
    • Builder: – Separates object construction from its representation.
    • Prototype: – A fully initialized instance to be copied or cloned.
    • Singleton: – A class in which only a single instance can exist.

    Factory(Method) pattern is one of the types of creational patterns. You can make out from the name factory itself it’s meant to construct and create something. In software architecture world factory pattern is meant to centralize creation of objects.

    Like other creational patterns, it deals with the problem of creating objects (product) without specifying the exact class of object that will be created. The factory method design pattern handles this problem by defining a separate method for creating the objects (CreateProduct), which subclasses can then override to specify the derived type of product that will be created.

    We call this a Factory Pattern since it is responsible for “Manufacturing” an Object. It helps instantiate the appropriate Subclass by creating the right Object from a group of related classes. The Factory Pattern promotes loose coupling by eliminating the need to bind application-specific classes into the code.

    Problem :

    • Sometimes, an Application (or framework) at runtime, cannot anticipate the class of object that it must create. The Application (or framework) may know that it has to instantiate classes, but it may only know about abstract classes (or interfaces), which it cannot instantiate. Thus the Application class may only know when it has to instantiate a new Object of a class, not what kind of subclass to create.
    • a class may want it’s subclasses to specify the objects to be created.
    • a class may delegate responsibility to one of several helper subclasses so that knowledge can be localized to specific helper subclasses.

    Example :

    public abstract class product { }
    
    public class Keyboard : product { }
    
    public class Mouse : product { }
    
    public abstract class Creator {
        public abstract product CreateProduct();
    }
    
    public class CreatorKeyboard : Creator{
        public override product CreateProduct() {
            return new Keyboard();
        }
    }
    
    public class CreatorMouse : Creator{
        public override product CreateProduct(){
            return new Mouse();
        }
    }
    
    //Application Code :
    
    List creators = new List();
    creators.Add(new CreatorKeyboard());
    creators.Add(new CreatorMouse());
     foreach (Creator creator in creators){
              product p = creator.CreateProduct();
           }

      

    Abstract factory expands on the basic factory pattern. Abstract factory helps us to unite similar factory pattern classes in to one unified interface. So basically all the common factory patterns now inherit from a common abstract factory class which unifies them in a common class. A factory class helps us to centralize the creation of classes and types. Abstract factory helps us to bring uniformity between related factory patterns which leads more simplified interface for the client.

    • Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
    • A hierarchy that encapsulates: many possible “platforms”, and the construction of a suite of “products”.
    • The new operator considered harmful.

    Example :

    The Example here has an implementation of an Abstract Factory as an Interface IAVDevice that has methods that can create an Audio object and a Video object. The client Codes against IAVDevice and gets IAudio and IVideo interfaces. Passing AVType.CD in the command line creates a family of cd objects (Audio and Video) and AVType.DVD creates a family of dvd objects (Audio and Video). The client doesn’t care which object (cd audio video or dvd audio video), IAVDevice interface returns as it codes against IAudio and IVideo interface.

    public interface IAudio { string GetSoundQuality { get; }}
    public interface IVideo{ string GetVideoQuality { get; }}
    public interface IAVDevice{
        IAudio GetAudio();
        IVideo GetVideo();
    }
    internal class cdAudio : IAudio{
        public string GetSoundQuality
        {
            get {return "CD Sound"; }
        }
    }
    
    internal class dvdAudio : IAudio{
        public string GetSoundQuality
        {
            get { return "DVD Sound"; }
        }
    }
    
    internal class cdVideo : IVideo{
        string IVideo.GetVideoQuality {
            get { return "CD Video"; }
        }
    }
    
    internal class dvdVideo : IVideo{
        string IVideo.GetVideoQuality {
            get { return "DVD Video"; }
        }
    }
    
    internal class CD : IAVDevice{
        public IAudio GetAudio() {
            return new cdAudio();
        }
        public IVideo GetVideo() {
            return new cdVideo();
        }
    }
    
    internal class DVD : IAVDevice{
        public IAudio GetAudio()
        {
            return new dvdAudio();
        }
    
        public IVideo GetVideo()
        {
            return new dvdVideo();
        }
    }
    
    public enum AVType{
        CD=0,
        DVD
    }
    
    public class AVMaker{
        public IAVDevice Make(AVType type)
        {
            switch (type) {
                case AVType.CD: return new CD();
                case AVType.DVD: return new DVD();
                default: return new CD();
            }
        }
    }
    
    //Application Code
    
    IAVDevice device = new AVMaker().Make(AVType.CD);
    string s = device.GetAudio().GetSoundQuality;
    string v = device.GetVideo().GetVideoQuality;
     
    Builder pattern falls under the type of creational pattern category. Builder pattern helps us to separate the construction of a complex object from its representation so that the same construction process can create different representations. Builder pattern is useful when the construction of the object is very complex. The main objective is to separate the construction of objects and their representations. If we are able to separate the construction and representation, we can then get many representations from the same construction.
    The intention is to abstract steps of construction of objects so that different implementations of these steps can construct different representations of objects.
     
    Example : Consider you have base Pizza class and you need to create several pizza objects which would have different properties set by the creator.
    /** "Product" */
    class Pizza
    {
        public string Dough { get; set; }
        public string Sauce { get; set; }
        public string Topping { get; set; }
    }
    
    /** "Abstract Builder" */
    abstract class PizzaBuilder
    {
        public Pizza pizza { get; protected set; }
    
        public void CreatePizza()
        {
            pizza = new Pizza();
        }
    
        public abstract void BuildDough();
        public abstract void BuildSauce();
        public abstract void BuildTopping();
    }
    
    /** "ConcreteBuilder" */
    class HawaiianPizzaBuilder : PizzaBuilder
    {
        public override void  BuildDough()
        {
            pizza.Dough = "Cross";
        }
    
        public override void BuildSauce()
        {
            pizza.Sauce = "Mild";
        }
    
        public override void BuildTopping()
        {
            pizza.Topping = "Ham+Pineapple";
        }
    }
    
    /** "ConcreteBuilder" */
    class SpicyPizzaBuilder : PizzaBuilder
    {
        public override void BuildDough()
        {
            pizza.Dough = "Pan Baked";
        }
    
        public override void BuildSauce()
        {
            pizza.Sauce = "Hot";
        }
    
        public override void BuildTopping()
        {
            pizza.Topping = "Pepperoni+Salami";
        }
    }
    
    /** "Director" */
    class Cook
    {
        public PizzaBuilder PizzaBuilder { get; set; }
    
        public Pizza Pizza { get { return PizzaBuilder.pizza; } }
    
        public void MakePizza()
        {
            PizzaBuilder.CreatePizza();
            PizzaBuilder.BuildDough();
            PizzaBuilder.BuildSauce();
            PizzaBuilder.BuildTopping();
        }
    }
    
    /** A given type of pizza being constructed. */
    static void Main(string[] args)
    {
        Cook cook = new Cook();
        cook.PizzaBuilder = new SpicyPizzaBuilder();
        cook.MakePizza();
        cook.PizzaBuilder = new HawaiianPizzaBuilder();
        cook.MakePizza();
    }

     

    Prototype pattern falls in the section of creational pattern. It gives us a way to create new objects from the existing instance of the object. In one sentence we clone the existing object with its data. By cloning any changes to the cloned object does not affect the original object value.

    There are two types of cloning for prototype patterns. One is the shallow cloning, in shallow copy only that object is cloned, any objects containing in that object is not cloned. For instance consider that we have a customer class and we have an address class aggregated inside the customer class. ‘MemberWiseClone’ will only clone the customer class ‘Customer’ but not the ‘Address’ class. So we added the ‘MemberWiseClone’ function in the address class also. Now when we call the ‘getClone’ function we call the parent cloning function and also the child cloning function, which leads to cloning of the complete object. When the parent objects are cloned with their containing objects it’s called as deep cloning and when only the parent is clones its termed as shallow cloning.

    This pattern is used to:

    • avoid subclasses of an object creator in the client application, like the abstract factory pattern does.
    • avoid the inherent cost of creating a new object in the standard way (e.g., using the ‘new’ keyword) when it is prohibitively expensive for a given application.

    To implement the pattern, declare an abstract base class that specifies a pure virtual clone() method. Any class that needs a “polymorphic constructor” capability derives itself from the abstract base class, and implements the clone() operation.

    The client, instead of writing code that invokes the “new” operator on a hard-coded class name, calls the clone() method on the prototype, calls a factory method with a parameter designating the particular concrete derived class desired, or invokes the clone() method through some mechanism provided by another design pattern.

    Example : Shallow copy prototype pattern

    public class Address { }
    
    public abstract class CloneType<T> where T : CloneType<T>
    {
        public T Clone()
        {
            return (T)this.MemberwiseClone();
    
        }
    }
    
    //Shallow Clone
    public class Customer : CloneType<Customer>
    {
        public string Name { get; set; }
        public Address MailingAddress { get; set; }
    }
    
    //Application
    
    Customer Prototype = new Customer();
    List<Customer> realCustomers = new List<Customer>();
    for (int i = 0; i <= 10; i++)
    {
        Customer customer = Prototype.Clone();
        customer.Name = "Rajneesh Noonia";
        customer.MailingAddress = new Address();
        realCustomers.Add(customer);
    }

     

    Singleton Pattern: There are situations in a project where we want only one instance of the object to be created and shared between the clients. No client can create an instance of the object from outside. There is only one instance of the class which is shared across the clients. Below are the steps to make a singleton pattern:-

    1) Define the constructor as private.
    2) Define the instances and methods as static.

    Example :

    //Thread-safe singleton example created at first call
    public sealed class Application
    {
        // Utilizes the get and set auto implemented properties.
        // Note that set; can be any other operator as long as it's
        // less accessible than public.
        public static Application Instance { get; private set; }
        // A static constructor is automatically initialized on reference
        // to the class.
        static Application() { Instance = new Application(); }
    }