Showing posts with label design-patterns. Show all posts
Showing posts with label design-patterns. Show all posts

Sunday, May 24, 2020

Breakout: a Circuit Breaker implementation in C#

A circuit breaker can help you improve the stability of your application by protecting calls to third party services; e.g. a web service, a network resource, a database, or any other component which can intermittently fail.

Its a fundamental pattern for protecting your system from all manner of integration point problems. It is a way to fail fast while there is a known problem with an integration point.

The circuit breaker pattern was first described in detail by Michael Nygard in the Stability Patterns chapter of his book "Release It!" Design and Deploy Production-Ready Software.

Breakout is a C# .NET implementation of Michael Nygard's Circuit Breaker state machine, using the Gang of Four's STATE design pattern. I've created a NuGet package for it here.

This implementation is thread safe, lightweight and easily adapted into your existing codebase. Unlike other circuit breaker implementations, it leaves the responsibility for calling the third party service with your client code. Your code only needs to inform the circuit breaker of the success or failure of every call to the third party service, via OperationSucceeded() and OperationFailed(). Check the README on github for example usage.


Breakout - State Machine Diagram

State Machine Explanation


The state machine starts in the CLOSED state. While in the CLOSED state, calls flow through as normal to the third party service. If the operation succeeds, the failure count is reset. If the operation fails, the failure count is incremented. When the failure count threshold is reached, the trip breaker action is performed, which transitions the state to OPEN.

While in the OPEN state, no calls flow through to the third party service. The caller just returns immediately, without performing the service call. After the open timeout has passed, the attempt reset action is performed, which transitions the state to HALF OPEN.

While in the HALF OPEN state, only one call is let through to the third party service. If the operation succeeds, we reset the circuit breaker which transitions the state to CLOSED. If the operation fails, the trip breaker action is performed, which transitions the state to OPEN.

UML Design


The design uses the Gang of Four's STATE design pattern.

Breakout - UML diagram

Follow @dodgy_coder on Twitter

Sunday, September 18, 2016

Lightweight IoT Command and Control

Many hobbyist IoT projects running on the Raspberry Pi (RPi) require a webserver running on the RPi which receives requests from a browser, where the client using the browser is connected either to the local WiFi network, or possibly (via a port forwarding setup), connected to the public Internet.

An alternative that is easy to setup, lightweight and low cost is one that makes use of Amazon's SQS (Simple Queue Service) to setup two queues. One queue is for commands - from a mobile application to the RPi. Another queue is for responses - from the RPi back to the mobile application. It results in a simple and easy to secure solution available over the public Internet. It requires no port forwarding - both endpoints make use of a client connection to Amazon AWS. Given the small amount of messages needed for typical hobbyist project, the SQS component will be covered by the AWS free tier.

Here's the high level design of the system ...

Lightweight IoT Command and Control
On the Raspberry Pi, a lightweight application is running that makes use of the excellent Python boto3 AWS SDK library. It is always waiting for a command to arrive in the command queue. As soon as it receives a command, it processes it and adds a response to the response queue.

On the mobile device an Android application is running that makes use of the AWS Mobile SDK for Android. When the user presses a command button, such as 'Open Garage Door', it adds a command to the command queue, and asynchronously waits for a response to arrive in the response queue. When it receives a response (e.g. the command's success or failure status), it updates the app's user interface.

Monday, June 15, 2015

The Default Files Folder Pattern

Software installation best practices

When you've got critical settings files that absolutely should never be overwritten or cleared back to defaults, this pattern has always worked well for me. It can apply to both Windows, Linux and Mac based software.

The installation method can either be a simple file copy utility/archive or something more complex like a Windows installer.

An example target structure might look something like this:

/MyApplication
    /bin           => Application binaries.
    /defaults      => A default version of all
settings files.
    /docs          => Documents or manuals.
    /settings      => Critical settings files.

             
The settings folder contains the critical settings files and is not part of the installer. The installer includes only the bin, defaults and docs folders. So installing the software only overwrites bin, defaults and docs, but never the settings. This applies equally to Windows installer packages - for this case, just don't include the settings folder in the Windows installer package. The defaults folder contains the default version of all of the the files expected in the settings folder.

Whenever the software accesses a particular file in settings the following lazy initialisation logic is used ...

- Does the settings folder exist?
    - Yes: Continue
    - No:  Create the folder and continue
   
- Does the file exist?
    - Yes: Open it
    - No:  Copy the file from the
defaults folder into the
           settings folder, then open it

By following the above logic, you ensure that an existing critical settings file is never overwritten.

From reading the latest report on the deadly Airbus A400M crash, its claimed that the cause was that their software installation procedure did the equivalent of overwriting a settings file or clearing it back to defaults. In this case, the settings file contained calibration parameters that were critical to the operation of 3 out of the 4 propeller engines.

Follow @dodgy_coder

Subscribe to posts via RSS

Tuesday, January 15, 2013

Big Ball of Mud Design Pattern


In "Big Ball of Mud", Brian Foote and Joseph Yoder propose that the default (and most common) software architecture in use is the "Big Ball of Mud" pattern and go on to discuss six additional patterns and activities that it gives rise to: "Throwaway Code", "Piecemeal Growth", "Keep it Working", "Shearing Layers", "Sweep it Under the Rug" and "Reconstruction".

Their original article is located here and can be downloaded in PDF form here: Big Ball of Mud by Brian Foote and Joseph Yoder [PDF download]

I have picked out what I think are the highlights of their article ...


Big Ball of Mud ... alias Shantytown or Spaghetti Code

Shantytowns are usually built from common, cheap materials with simple tools and using unskilled labor. The construction and maintenance of the shantytown is labor intensive, and there is little or no labor specialization - each builder must be a jack of all trades. There's no overall planning, or regulation of future growth.

Too many of our software systems are, architecturally, little more than shantytowns. Investment in tools and infrastructure is often inadequate and the tools that are used are primitive. Parts of the system grow unchecked, and the lack of architecture and planning allows problems in one part of the system to erode and pollute adjacent portions. Deadlines loom like monsoons, and architectural elegance seems unattainable.

The time and money to chase perfection are seldom available and there is a survival at all costs attitude, to do what it takes to get the software working and out the door on time. The biggest cost borne by the Big Ball of Mud development is the lack of a decent architecture.


Common features of Big Ball of Mud Code
  • Data structures are haphazardly constructed, or non-existent.
  • Everything talks to everything else.
  • Important state data is global.
  • State data is passed around though Byzantine back channels that circumvent the system's original structure.
  • Variable and function names are uninformative and misleading.
  • Functions use global variables extensively, as well as long lists of poorly defined parameters.
  • Functions themselves are lengthy and convoluted, and perform several unrelated tasks.
  • Code duplication.
  • The flow of control is hard to understand, and difficult to follow.
  • The programmer’s intent is next to impossible to discern.
  • The code is simply unreadable, and borders on indecipherable.
  • The code exhibits the unmistakable signs of patch after patch at the hands of multiple maintainers, each of whom barely understood the consequences of what he or she was doing.
  • Did we mention documentation? What documentation?

Working with Big Ball of Mud Code

Some software engineers come to regard life with the Big Ball of Mud as normal and become skilled at learning to navigate these quagmires, and guiding others through them. Over time, this symbiosis between architecture and skills can change the character of the organization itself, as swamp guides become more valuable than architects.

As per Conway's Law, architects depart in futility, while engineers who have mastered the muddy details of the system they have built, prevail. The code becomes a personal fiefdom, since the author care barely understand it anymore, and no one else can come close. Once simple repairs become all day affairs, as the code turns to mud.


Throwaway Code ... alias Quick Hack or Protoduction

While prototyping a system, you're normally unconcerned with how elegant or efficient your code is. You plan that you will only use it to prove a concept and once the prototype is done, the code will be thrown away and written properly. As the time nears to demonstrate the prototype, the temptation to load it with impressive but utterly inefficient realizations of the system’s expected eventual functionality can be hard to resist. Sometimes, this strategy can be a bit too successful. The client, rather than funding the next phase of the project, may slate the prototype itself for release.

This quick-and-dirty coding is often rationalized as being a stopgap measure. More often than not, the time is never found for this follow up work. The code languishes, while the product flourishes. It becomes a protoduction - a prototype that gets used in production.

Once it becomes evident that the throwaway code is going to be around for a while, you can turn your attention to improving its structure, either through an iterative process of Piecemeal Growth, or via a fresh draft, as discussed in the Reconstruction pattern below.


Piecemeal Growth ... alias Refactoring

Successful software attracts a wider audience, which can, in turn, place a broader range of requirements on it.

When designers are faced with a choice between building something elegant from the ground up, or undermining the architecture of the existing system to quickly address a problem, architecture usually loses.

In the software world, we deploy our most skilled, experienced people early in the lifecycle. Later on, maintenance is often relegated to junior staff, and resources can be scarce. The so-called maintenance phase is the part of the lifecycle in which the price of the fiction of master planning is really paid. It is maintenance programmers who are called upon to bear the burden of coping with the ever widening divergence between fixed designs and a continuously changing world.

Piecemeal growth can be undertaken in an opportunistic fashion, starting with the existing, living, breathing system, and working outward, a step at a time, in such a way as to not undermine the system’s viability. You enhance the program as you use it. Massive system-wide changes are avoided - instead, change is broken down into small, manageable chunks.


Keep It Working ... alias Continuous Integration

Businesses become critically dependent on their software and computing infrastructures. There may be times where taking a system down for a major overhaul can be justified, but usually, doing so is fraught with peril. Therefore, do what it takes to maintain the software and keep it going. Keep it working.

This approach can be used for both minor and major modifications. Large new subsystems might be constructed off to the side, perhaps by separate teams, and integrated with the running system in such a way as to minimize disruption.

A development build of each product can be performed at regular intervals, such as daily or even more often via an automated build tool. Another vital factor in ensuring a system's continued vitality is a commitment to continuous testing, which can be integrated into the automated build process.


Shearing Layers

Software never stands still. It is often called upon to bear the brunt of changing requirements, because, being as that it is made of bits, it can change.

Over time, the software's frameworks, abstract classes, and components come to embody what we've learned about the structure of the domains for which they are built. More enduring insights gravitate towards the primary structural elements of these systems and change rarely. Parts which find themselves in flux are spun out into the data, where users can interact with them. Software evolution becomes like a centrifuge stirred by change. The layers that result, over time, can come to a much truer accommodation with the forces that shaped them than any top-down planning could have devised.


Sweeping It Under The Rug

At first glance, a Big Ball of Mud can inspire terror and despair in the hearts of those who would try to tame it. The first step on the road to architectural integrity can be to identify the disordered parts of the system, and isolate them from the rest of it.

Overgrown, tangled, haphazard spaghetti code is hard to comprehend, repair, or extend, and tends to grow even worse if it is not somehow brought under control. If you can’t easily make a mess go away, at least cordon it off. This restricts the disorder to a fixed area, keeps it out of sight, and can set the stage for additional refactoring.


Reconstruction ... alias Total Rewrite

One reason to start again might be that the previous system was written by people who are long gone. Doing a rewrite provides new personnel with a way to reestablish contact between the architecture and the implementation. Sometimes the only way to understand a system it is to write it yourself. Doing a fresh draft is a way to overcome neglect. Issues are revisited. A fresh draft adds vigor. You draw back to leap. The quagmire vanishes. The swamp is drained.

When a system becomes a Big Ball of Mud, its relative incomprehensibility may hasten its demise, by making it difficult for it to adapt. It can persist, since it resists change, but cannot evolve, for the same reason. Instead, its inscrutability, even when it is to its short-term benefit, sows the seeds of its ultimate demise.


The above are highlights from the original article, which is located here ... Big Ball of Mud by Brian Foote and Joseph Yoder [PDF download]


Some further reading on Programmers.StackExchange ...

I've inherited 200K lines of spaghetti code — what now?
How to convince my boss that quality is a good thing to have in code?
How to keep a big and complex software product maintainable over the years?
Techniques to re-factor garbage and maintain sanity?
When is code “legacy”?
What is negative code?


Some related books ...

Working Effectively With Legacy Code ... by Michael Feathers [Amazon]
Refactoring: Improving the Design of Existing Code ... by M. Fowler, K. Beck, et al. [Amazon]
Design Patterns: Elements of Reusable Object-Oriented Software ... by the Gang of Four [Amazon]
Patterns of Enterprise Application Architecture ... by Martin Fowler [Amazon]
Domain Driven Design: Tackling Complexity in the Heart of Software ... by Eric Evans [Amazon]
Head First Design Patterns by E. Freeman, E. Freeman, et al. [Amazon]