Monday, June 25, 2018

Thinking about Software Architecture & Design : Part 13


Harold Abelson, co-author of the seminal tome Structure and Interpretation Of Computer Programs (SICP) said that “programs must be written for people to read, and only incidentally for machines to execute.”

The importance of human-to-human communication over human-to-machine is even more true in Software Architectures, where there is typically another layer or two of resolution before machines can interpret the required architecture.

Human-to-human communications is always fraught with potential for miscommunications and the reasons for this run very deep indeed. Dig into this subject and it is easy to be amazed that anything can be communicated perfectly at all. It is a heady mix of linguistics, semiotics, epistemology and psychology. I have written before (for example, in the “What is Law Series - http://seanmcgrath.blogspot.com/2017/06/what-is-law-part-14.html) about the first three of these, but here I want to talk about the fourth – psychology.

I had the good fortune many years ago to stumble upon the book Inevitable Illusions by Massimo Piattelli-Palmarini and it opened my mind to the idea that there are mental concepts we are all prone to develop, that are objectively incorrect – yet unavoidable. Think of your favorite optical illusion. At first you were amazed and incredulous. Then you read/discovered how it works. You proved to your own satisfaction that your eyes were deceiving you. And yet, every time you look at the optical illusion, your brain has another go at selling you on the illusion. You cannot switch it off. No amount of knowing how you are being deceived by your eyes will get your eyes to change their minds, so to speak.

I have learned over the years that some illusions about computing are so strong that it is often best to incorporate them into architectures rather than try to remove them. For example, there is the “send illusion”. Most of the time when there is an arrow between A and B in a software architecture, there is a send illusion lurking. The reason being, it is not possible to send digital bits. They don't move through space. Instead they are replicated. Thus every implied “send” in an architecture can never be a truly simple send operation and it involves at the very least, a copy followed by a delete. 

Another example is the idea of a finite limit to the complexity of business rules. This is the very (very!) appealing idea that with enough refinement, it is possible to arrive at a full expression of the business rules that express some desirable computation. This is sometimes true (especially in text books) which adds to the power of the inevitable illusion. However, in many cases this is only true if you can freeze requirements – a tough proposition – and often is impossible even then. For example in systems where there is a feedback loop between the business rules and the data creating a sort of “fractal boundary” that the corpus of business rules can never fully cover.

I do not let these concerns stop me from using concepts like “send” and “business rule repository” in my architectures because I know how powerfully these concepts are locked into all our minds. However, I do try to conceptualize them as analogies and remain conscious of the tricks my mind plays with them. I then seek to ensure that the implementation addresses the unavoidable delta between the inevitable illusion in my head and the reality in the machine.


Thursday, June 14, 2018

Thinking about Software Architecture & Design : Part 12


The word “flexible” gets used a lot in software architecture & design. It tends to get used in a positive sense. That is, "flexibility" is mostly seen as a good thing to have in your architecture.

And yet, flexibility is very much a two edged sword. Not enough of it, and your architecture can have difficulty dealing with the complexities that typify real world situations. Too much of it and your architecture can be too difficult to understand and maintain. The holy grail of flexibility, in my opinion, is captured in the adage that “simple things should be simple, and hard things should be possible.”.

Simple to say, hard to do. Take SQL for example, or XSLT or RPG...they all excel at making simple things simple in their domains and yet, can also be straitjackets when more complicated things come along. By “complicated” here I mean things that do not neatly fit into their conceptual models of algorithmics and data.

A classic approach to handling this is to allow such systems to be embedded in Turing Complete Programming language. i.e. SQL inside C Sharp. XSLT inside Java etc. The Turing Completeness of the programming language host ensures that the “hard things are possible” while the core – and now “embedded system” - ensures that the simple things are simple.

Unfortunately what tends to happen is that the complexity of the real world chips away at the split between simple and complex and, often times, such hybrid systems evolve into Turing Complete hosts. i.e. over time, the embedded system for handling the simple cases, is gradually eroded and then one day, you wake up to find that it is all written in C# or Java or whatever and the originally embedded system is withering on the vine.

A similar phenomenon happens on the data side where an architecture might initially by 98% “structured” fields but over time, the “unstructured” parts of its data model grow and grow to the point where the structured fields atrophy and all the mission critical data migrates over to the unstructured side. This is why so many database-centric systems organically grow memo fields, blob fields or even complete distinct document storage sub-systems over time, to handle all the data that does not fit neatly into the “boxes” of the structured fields.

Attempting to add flexibility to the structured data architecture tends to result in layers of abstraction that people have difficult following. Layers of pointer indirection. Layers of subject/verb/object decomposition. Layers of relationship reification and so on....

This entropy growth does not happen overnight. The complexity of modelling the real world chips away at designs until at some point there is an inflection. Typically this point of inflection manifests in a desire to “simplify” or “clean up” a working system. This often results in a new architecture that incorporates the learnings from the existing system and then the whole process repeats again. I have seen this iteration work at the level of decades but in more recent years the trend appears to be towards shorter and short cycle times.

This cyclic revisiting of architectures begs the obvious teleological question about the end point of this cycle. Does it have an end? I suspect not because, in a Platonic sense, the ideal architecture can be contemplated but cannot be achieved in the real world.

Besides, even if it could be achieved, the ever-changing and monotonically increasing complexity of the real world ensures that a perfect model for time T can only be achieved at some future time-point T+N, by which time, it is outdated and has been overtaken by the every shifting sands of reality.


So what is an architect to do if this is the case? I have come to the conclusion that it is very very important to be careful to label anything as an immutable truth in an architecture. All nouns, verbs, adjectives etc. that sound to you like that are “facts” of the real world, will, at some point bend under the weight of constant change and necessarily incomplete empirical knowledge.

The smaller the set of things you consider immutable facts, the more flexible your architecture will be. By all means, layer abstractions on top of this core layer. By all means add Turing Completeness into the behavioral side of the model. But treat all of these higher layers as fluid. It is not that they might need to change it is that they will need to change. It is just a question of time.

Finally, there are occasions where the set of core facts in your model is the empty set! Better to work with this reality than fight against it because entropy is the one immutable fact you can absolutely rely on. Possibly the only thing you can have an the core of your architecture and not worry about it being invalidated by the arrival of new knowledge or the passage of time.


Friday, June 01, 2018

Thinking about Software Architecture & Design : Part 11


It is said that there are really only seven basic storylines and that all stories can either fit inside them or be decomposed into some combination of the basic seven. There is the rags-to-riches story. The voyage and return story. The overcoming the monster story...and so on.

I suspect that something similar applies to Software Architecture & Design. When I was a much younger practitioner in this field, I remember a very active field with new methodologies/paradigms coming along on a regular basis. Thinkers such as Yourdon, de Marco, Jackson, Booch, Hoare, Dijkstra, Hohpe distilled the essence of most of the core architecture patterns we know of today.

In more recent years, attention appears to have moved away from the discovery/creation of new architecture patterns and architecture methodologies towards concerns closer to the construction aspects of software. There is an increasing emphasis on two way flows in the creation of architectures– or perhaps circular flows would be a better description. i.e. iterating backwards from, for example user stories, to the abstractions required to support the user stories. Then perhaps a forward iteration refactoring the abstractions to get coverage of the required user stories with less “moving parts” as discussed before.

There has also been a marked trend towards embracing the volatility of the IT landscape in the form of proceeding to software build phases with “good enough” architectures and the conscious decision to factor-in the possibility of needing complete architecture re-writes in ever short time spans.

I suspect this is an area where real world physical architecture and software architecture fundamentally differ and the analogy breaks down. In the physical world, once the location of the highway is laid down and construction begins, a cascade of difficult-to-reverse events starts to occur in parallel with the construction of the highway. Housing estates and commercial areas pop up close to the highway. Urban infrastructure plans – perhaps looking decades into the future – are created predicated on the route of the highway and so on.

In software, there are often similar amount of knock-on effects to architecture changes but when these items are themselves primarily software, rearranging everything based on a architecture is more manageable. Still likely a significant challenge, but more doable because software is, well “softer” than real world concrete, bricks and mortar.

My overall sense of where software architecture is today is that it revolves around the question : “how can we make it easier to fundamentally change the architecture in the future?” The fierce competitive landscape for software has combined with cloud computing to fuel this burning question.

Creating software solutions with very short (i.e. weeks) time horizons before they change again is now possible and increasingly commonplace. The concept of version number is becoming obsolete. Today's software solution may or may not be the same as the one you interacted with yesterday and it may, in fact, be based on an utterly different architecture under the hood than it was yesterday. Modern communications infrastructure, OS/device app stores, auto-updating applications, thin clients...all combine to create a very fluid environment for modern day software architectures to work in.

Are there new software patterns still emerging since the days of data flow and ER diagrams and OOAD? Are we just re-combining the seven basic architectures in a new meta-architecture which is concerned with architecture change rather than architecture itself? Sometimes I think so.

I also find myself wondering where we go next if that is the case. I can see one possible end point for this. An end-point which I find tantalizing and surprising in equal measure. My training in software architecture – the formal parts and the decades of informal training since then – have been based on the idea that the fundamental job of the software architect is to create a digital model – a white box – of some part of the real world, such that the model meets a set of expectations in terms of its interaction with its users (which may, be other digital models).

In modern day computing, this idea of the white box has an emerging alternative which I think of as the black box. If a machine could somehow be instructed to create the model that goes inside the box – based purely on an expression of its required interactions with the rest of the world – then you basically have the only architecture you will ever need for creating what goes into these boxes. The architecture that makes all the other architectures unnecessary if you like.

How could such a thing be constructed? A machine learning approach, based on lots and lots of input/output data? A quantum computing approach which tries an infinity of possible Turing machine configurations, all in parallel? Even if this is not possible today, could it be possible in the near future? Would the fact that boxes constructed this way would be necessarily black – beyond human comprehension at the control flow level – be a problem? Would the fact that we can never formally prove the behavior of the box be a problem? Perhaps not as much as might be initially thought, given the known limitations of formal proof methods for traditionally constructed systems. After all, we cannot even tell if a process will halt, regardless of how much access we have to its internal logic. Also, society seems to be in the process of inuring itself to the unexplainability of machine learning – that genie is already out of the bottle. I have written elsewhere (in the "what is law?" series - http://seanmcgrath.blogspot.com/2017/07/what-is-law-part-15.html) that we have the same “black box” problem with human decision making anyway).

To get to such a world, we would need much better mechanism for formal specification. Perhaps the next generation of software architects will be focused on patterns for expressing the desired behavior of the box, not models for how the behavior itself can be achieved. A very knotty problem indeed but, if it can be achieved, radical re-arrangements of systems in the future could start and effective stop with updating the black box specification with no traditional analysis/design/ construct/test/deploy cycle at all.

Monday, May 28, 2018

Thinking about Software Architecture & Design : Part 10


Once the nouns and verbs I need in my architecture start to solidify, I look at organizing them across multiple dimensions. I tend to think of the noun/verb organization exercise in the physical terms of surface area and moving parts. By "surface area" I mean minimizing the sheer size of the model. I freely admin that page count is a crude-sounding measure for a software architecture, but I have found over the years that the total size of the document required to adequately explain the architecture is an excellent proxy for its total cost of ownership.

It is vital, for a good representation of a software architecture, that both the data side and the computation side are covered. I have seen many architectures where the data side is covered well but the computation side has many gaps. This is the infamous “and then magic happens” part of the software architecture world. It is most commonly seen when there is too much use of convenient real world analogies. i.e. thematic modules that just snap together like jigsaw/lego pieces, data layers that sit perfectly on top of each other like layers of a cake, objects that nest perfectly inside other objects like Russian Dolls etc.

When I have a document that I feel adequately reflects both the noun and the verb side of the architecture, I employ a variety of techniques to minimize its overall size. On the noun side, I can create type hierarchies to explore how nouns can be considered special cases of other nouns. I can create relational de-compositions to explore how partial nouns can be shared by other nouns. I will typically “jump levels” when I am doing this. i.e. I will switch between thinking of the nouns in purely abstract terms (“what is a widget really” to thinking about them in physical terms: “how best to create/read/update/delete widgets?”). I think of it as working downwards towards implementation an upwards towards abstraction at the same time. It is head hurting at times, but in my experience produces better practical results that the simpler step-wise refinement approach of moving incrementally downwards from abstraction to concrete implementation.

On the verb side, I tend to focus on the classic engineering concept of "moving parts". Just as in the physical world, it has been my experience that the smaller the number of independent moving parts in an architecture, the better. Giving a lot of thought to opportunities to reduce the total number of verbs required pays handsome dividends. I think of it in terms of combinatorics. What are the fundamental operators I need from which, all the other operators can be created by combinations of the fundamental operators? Getting to this set of fundamental operators is almost like finding the architecture inside the architecture.

I also think of verbs in terms of complexity generators. Here I am using the word “complexity” in the mathematical sense. Complexity is not a fundamentally bad thing! I would argue that all system behavior has a certain amount of complexity. The trick with complexity is to find ways to create the amount required but in a way that allows you to be in control of it. The compounding of verbs is the workhorse for complexity generation. I think of data as a resource that undergoes transformation over time. Most computation – even the simplest assignment of the value Y to be the value Y + 1 has an implicit time dimension. Assuming Y is a value that lives over a long period of time – i.e. is persisted in some storage system – then Y today is just the compounded result of the verbs applied to it from its date of creation.

There are two main things I watch for as I am looking into my verbs and how to compound them and apply them to my nouns. The first is to always include the ability to create an ad-hoc verb “by hand”. By which I mean, always having the ability to edit the data in nouns using purely interactive means. This is especially important in systems where down-time for the creation of new algorithmic verbs is not an option.

The second is watching out for feedback/recursion in verbs. Nothing generates complexity faster than feedback/recursion and when it is it used, it must be used with great care. I have a poster on my wall of a fractal with its simple mathematical formula written underneath it. It is incredible that such bottomless complexity can be derived from such a harmless looking feedback loop. Using it wisely can produce architectures capable of highly complex behaviors but with small surface areas and few moving parts. Used unwisely.....

Monday, May 21, 2018

Thinking about Software Architecture & Design : Part 9

I approach software architecture through the medium of human language. I do make liberal use of diagrams but the diagrams serve as illustrators of what, to me, is always a linguistic conceptualization of a software architecture. In other words, my mental model is nouns and verbs and adjectives and adverbs. I look for nouns and verbs first. This is the dominant decomposition for me. What are that things that exist in the model? Then I look for what actions are performed on/by the things in the model. (Yes, the actions are also “things” after a fashion...)

This first level of decomposition is obviously very high level and yet, I find it very useful to pause at this level of detail and do a gap analysis. Basically what I do is I explain the model to myself in my head and look for missing nouns and verbs. Simple enough.

But then I ask myself how the data that lives in the digital nouns actually gets there in the first place. Most of the time when I do this, I find something missing in my architecture. There are only finite number of ways data can get into a digital noun in the model. A user can enter it, an algorithm can compute it, or an integration point can supply it. If I cannot explain all the data in the model through the computation/input/integration decomposition, I am most likely missing something.

Another useful question I ask at this level of detail relates to where the data in the nouns goes outside the model. In most models, data flows out at some point to be of use i.e. it hits a screen or a printout or an outward bound integration point. Again, most of the time when I do this analysis, I find something missing – or something in the model that does not need to be there at all.

Getting your nouns and verbs straight is a great first step towards what will ultimately take the form of objects/records and methods/functions/procedures. It is also a great first step if you are taking a RESTian approach to architecture as the dividing line between noun-thinking and verb-thinking is the key difference between REST and RPC in my experience.

It is hard to avoid prematurely clustering nouns into types/classes as our brains appear to be wired towards organizing things into hierarchies. I do this because I find that as soon as I start thinking hierarchically, I close off the part of my brain that is open to alternative hierarchical decompositions. I try to avoid that because in my experience, the set of factors that steer an architecture towards one hierarchy instead of another are practical ones, unrelated to “pure” data modelling. i.e. concerns related to organizational boundaries, integration points, cognitive biases etc.

Take the time to explore as many noun/verb decompositions as you can because as soon as you pick one and start to refine the model, it becomes increasingly hard to think “outside the box” of your own architecture.

Friday, May 18, 2018

Thinking about Software Architecture & Design : Part 8


It is common practice to communicate software architectures using diagrams, but most diagrams, in my experience are at best rough analogies of the architecture rather than faithful representations of it.

All analogies break down at some point. That is why we call them “analogies”. It is a good idea to understand where your analogies break down and find ways to compensate.

In my own architecture work, the main breakdown point for diagrams is that architectures in my head are more like movies than static pictures. In my minds eye, I tend to see data flowing. I tend to see behaviors – both human and algorithmic – as animated actors buzzing around a 3D space, doing things, producing and consuming new data. I see data flowing, data flowing out, data staying put but changing shape over time, I see feedback loops where data flows out but then comes back in again. I see the impact of time in a number of different dimensions. I see how it relates to the execution paths of the system. I see how it impacts the evolution of the system as requirements change. I see how it impacts the dependencies of the system that are outside of my control e.g. operating systems etc.

Any static two dimensional picture or set of pictures, that I take of this architecture necessarily leaves a lot of information behind. I liken it to taking a photo of a large city at 40,000 feet and then trying to explain all that is going on in that city, through that static photograph. I can take photos from different angles and that will help but, at the end of the day, what I would really like is a movable camera and the ability to walk/fly around the “city” as a way of communicating what is going on in it, and how it is architected to function. Some day...

A useful rule of thumb is that most boxes, arrows, straight lines and layered constructions in software architecture diagrams are just rough analogies. Boxes separating say, organizations in a diagram, or software modules or business processes are rarely so clean in reality. A one way arrow from X to Y is probably in reality a two way data flow and it probably has a non-zero failure rate. A straight line separating, say “valid” from “invalid” data records probably has a sizable grey area in the middle for data records that fuzzily sit in between validity and invalidity. And so on.

None of this is in any way meant to suggest that we stop using diagrams to communicate and think about architectures. Rather, my goal here is just to suggest that until we have better tools for communicating what architectures really are, we all bear in mind the limited ability of static 2D diagrams to accurately reflect them.

Thursday, May 10, 2018

Thinking about Software Architecture & Design : Part 7


The temptation to focus a lot of energy on the one killer diagram that captures the essence of your architecture is strong. How many hours have I spent in Visio/Powerpoint/draw.io on “the diagram”? More than I would like to admit to.

Typically, I see architectures that have the “main diagram” and then a series of detail diagrams hidden away, for use by implementation and design teams. The “main diagram” is the one likely to go into the stakeholder presentation deck.

This can works fine when there are not many stakeholders and organizational boundaries are not too hard to traverse. But as the number of stakeholders grows, the power of the single architectural view diminishes. Sometimes, in order to be applicable to all stakeholders, the diagram becomes so generic that it really says very little i.e. the classic three-tiered architecture or the classic hub-and-spoke or the peer-to-peer network. Such diagrams run the risk of not being memorable by any of the stakeholders, making it difficult for them to get invested in it.

Other times, the diagram focuses on one particular “view” perhaps by putting one particular stakeholder role in the center of the diagram, with the roles of the other stakeholders surrounding the one in the middle.

This approach can be problematic in my experience. Even if you take great pains to point out that there is no implied hierarchy of importance in the arrangement of the diagram, the role(s) in the middle of the diagram will be seen as more important. It is a sub-conscious assessment. We cannot help it. The only exception I know of is when flow-order is explicit in the diagram but even then whatever is in the middle of the diagram draws our attention.

In most architectures there are “asks” of the stakeholders. The best way to achieve  these “asks” in my experience is to ensure that each stakeholder gets their own architecture picture, that has their role in the center in the diagram, with all other roles surrounding their part in the big picture.

So, for N stakeholders there are N "main views" - not just one. All compatible ways of looking at the same thing. All designed to make it easier for each stakeholder to answer the “what does this mean for me?” question which is always there – even if it is not explicitly stated.

Yes, it is a pain to manage N diagrams but you probably have them anyway – in the appendices most likely, for the attention of the design and implementation phase. My suggestion is to take them out of the appendices and put them into the stakeholder slide deck.

I typically present two diagrams to each stakeholder group. Slide one is the diagram that applies to all stakeholders. Slide two is for the stakeholder group I am presenting to. As I move around the different stakeholder meetings, I swap out slide number two.