Yada yada on Software Development


A Question of Scale

In the previous post we decided that there are a number of desirable properties that we'd like a software system to have. I'll quickly repeat the ones I mentioned; A system should be Functional, Testable, Robust, Monitorable, Deployable, Scalable, Adaptable, Efficient and Elegant.

(There's probably ample opportunity to create a catchy and memorable abbreviation out of these words, but let's not.)

These properties can be achieved at different scales, or levels. By that I mean that they are affected by architectural (large scale) and design (medium scale) decisions as well as implementation (small scale) decisions.

So, in this series of articles, I am using the word "design" in a very broad sense, and not something limited to the designer role. These design principles is about reasoning how to create software, not just by hacking away on the problem at hand, but instead by having a plan at a higher level, describing how the system should be built to get a professional result by design (i.e. on purpose, not by accident). This plan should then affect everyone on the development team.

I could have called this series "friendly advice on how to increase the level of professionalism in your software development effort", but choose to use the word "design" to the same general meaning.

Role playing

First I'd like to elaborate a little on the differences and interconnections between the roles of architect, designer and implementer, as I will not place much focus on these individual roles later in this series.

I consider these roles to be more or less a matter of on which scale one operates on. The architect considers issues on the largest scale, how the whole will operate as a function of the major components, while the implementers (craftsmen) considers the issues on the smallest scale, performing the practical construction of the needed parts according to the designs.

The designer and architect roles are really only needed because sufficiently large systems have far too many "moving parts" for any one person to understand the entire system in any detail, and it becomes more efficient having some people focus on the general higher level goals, and delegate the lower level details on how to reach specific goals to others focusing on their part of the system.

How are these things connected?

The smaller the system, the less need for designer and architect skills on the team. If you are building a dog house, you don’t need to be an architect. However, as soon as the system complexity increases and it becomes composed of several cooperating services or applications, those skills become important. It’s hard to rescue bad architecture with good design, or a terrible design with good implementation. (On the other hand it's simple to wreck even the best designs with a lousy implementation, anyone can do that!)

Analogies are often made between software construction and building construction. I guess that's because building construction is easy to visualize, and that it shares roles and questions of scale with software construction.

The Sydney Opera House under constructionSo, let's for a moment consider the Sydney Opera house. Surely an example of grand architecture! But is it also an example of grand design, and grand implementation?

I have no idea, but my point here is that at smaller scales, it could be a real mess! It does not follow that anything is superbly implemented at lower levels of detail, even though we can agree it is grand in the larger scales.

For example, the electrical wiring could be installed in an amateurish and unsafe manner, and placed where there are no easy access for maintenance workers.

The white ceramic tiles (manufactured in Sweden, by the way) could have been unprofessionally set on the roof in a way that let water in underneath, letting rust and mold starting to do damage to the building.

So the architect and designer(s) could have been doing a good job, but the craftsmen could have been amateurs, causing a whole lot of problems, that may last for the entire lifetime of the building.

And even if the architecture makes it a fantastic landmark, it could be that it is not optimally functional for an opera house. The Wikipedia entry indeed suggests that there are problems with the acoustics in the two major halls. But apparently the customer wanted both a landmark and an opera house, and then compromises was made.

This leads us to my next post in this series, where I’ll get to the first, and perhaps most important property of any system; being functional!

Filed under: Design No Comments

Principles of Software Design

Software should be well designed, right? What then is well designed software? I'd say it's much easier to spot badly designed software, than to postulate what constitutes well designed software. Nevertheless, I'm going to give it a try. I'll also try to provide illustrative examples and justifications for my arguments.

However, I think we all can agree that the answer to what constitutes good design depends heavily on the context and purpose the software is developed for.

Are we tasked with building a service without a user interface, a web or desktop application, a game or an operating system, a smart-phone app, or an embedded system? Will it be stand-alone or part of a larger system? Will it be single user or multiuser, a commercial product or an in-house solution, will it run unattended, is it life-critical? Will it handle 100 KB or 100 TB of data per day? What is the cost of failures? How much data loss is acceptable? How much downtime is acceptable? What are the performance goals?

Design decisions that would be considered "good" (or "good enough") for one kind of system, might be detrimental to another.

Target software

So let's define what target software I'm considering in this discussion of "good design".

I'm most familiar designing or reviewing software in what we can call the "medium to large" scale, where the systems are comprised of several interacting components, such as desktop or web applications, web and windows services, and relational databases, loosely connected together in order to form a whole cohesive system.

My experience is that most systems have very few, if any, constraints that are really really hard, which must never be broken. This means in practice that nothing will be life critical, and the cost of failure is not overwhelming. A small amount of downtime may also be acceptable by the users. We are probably not dealing with data sets of hundreds of terabytes, and are not handling extremely sensitive or secret information.

The principles I want to discuss may also not be equally valid for very large scale systems such as MMORPGs, or the very small hobbyist scale such as the Sudoku solver you write for fun, but will in my opinion still be applicable to a rather wide range of enterprise or business software, from single user desktop applications, to web sites with tens of thousands of users, or business critical information processing services running as windows services or internet-facing web services.

The principles

Now let's get closer to the actual design discussions, shall we?

Experience have taught me a few things about software design, and I think that there are a number of desirable properties that we'd like our system to have. The following lists some of the most important ones:

  • Functional - able to provide the required functionality.
  • Testable - so we can ensure the system does what we want it do to.
  • Robust - able to handle and recover from failures.
  • Monitorable - the status of the system can be observed from the outside while it is running.
  • Deployable - easy to move from the development environment to the production environment.
  • Scaleable - able to gracefully handle a growing amount of data and users.
  • Adaptable - able to handle changes in the requirements or run-time environment.
  • Efficient - able to make the most out of the available computing resources.
  • Elegant - attains perfection not when there's no more to add, but when there's no more to remove.

My plan is to expand on the characteristics of these individual design properties in a series of future posts. I could probably expand on this list, but these are the really important ones, and we have to start somewhere, don't we? If I come up with more desirable properties, I'll have to come back to them later, or I'll never get started. This is a blog, not a book, after all.

Feedback from users or by observation is invaluable for the evaluation of a design (be it your own, or any design you know and understand well). Negative feedback on the design is a powerful motivator to design something better next time. Positive feedback helps reinforce the good decisions made, and we are likely to try to re-use good ideas the next time around.

Filed under: Design No Comments