In the previous article, I tried to describe how I see a software architect, and how he or she would operate within a team or organization. One topic I also wanted to discuss is the type of work a software architect would actually do. However, I decided to save that for a later article, so that is where we are today.
As you could read in the previous article, ‘software architecture’ is quite vague and ‘meta’. Software architecture happens at a high-level of abstraction by nature, so trying to describe it will always remain vague. And that’s not just me. I followed a Software Architecture course at university, and it was just as vague. They made you aware of this however. The course concentrated only on a case study where requirements and constraints had to be extracted from the input of various parties, and had to be translated into an architecture document (various diagrams and explanations at various levels, some aimed at the customer, some at end-users, some at developers etc. Also various usage scenarios and a risk analysis/evaluation of the architecture). No actual programming was involved.
That is somewhat artificial of course. The architect’s work is rarely that cut-and-dry in practice. Firstly, not all software can just be designed ‘on paper’ like that. Or at least, the chances of getting it right the first time would be slim. I find that often when I need to design new software, I am introduced to various technologies that I have not used before, and therefore I do not know how they would behave in an architecture beforehand. To give a simple example: if you were to design a C# application, you might make a lot of use of multithreading and Tasks (thread pooling). But if you were to design a browser-based JavaScript application, the usage of threading is very limited, so you would choose a different route for your design.
Secondly, in practice, especially these days with Agile, DevOps, cross-functional teams and all that, the architect is generally also a team member, and will also participate in development, as I’ve already mentioned in the previous article.
So let’s make all this a little more practical. The guideline I use is that the architect “solves problems”. And I mean that quite literally. That is, the architect takes the high-level problem, and translates it to a working solution. My criterion here is that the problem is “solved”, as in: once the code has been written, the problem is no longer a problem. There is now a library, framework or toolset that handles the problem in a straightforward way (I’m sure most developers have found those ‘headache’ products that just keep generating new bugs, no matter how much you try to fix them, and never performed satisfactorily to begin with. A real architect delivers problem-free products).
That does not necessarily mean that the architect writes the actual code. It means that the architect reduces the high-level abstraction and complexity, and translates it to the level required for the development team to build the solution. What level that is exactly, depends on the capabilities of the team. Worst-case, the architect will actually have to write some code entirely by himself.
But if you think about it that way, as a developer you are using such libraries, frameworks and toolsets all the time. You don’t write your own OS, compiler, database, web browser etc. Other people have solved these problems for you. Problems that may be too difficult for the average developer to solve by themselves anyway. Each of these topics requires highly skilled developers. And even then, these developers may be skilled in only one or perhaps a few of these topics at best. That is, it’s unlikely for an OS expert to also be an expert at database, compiler, browser etc technology. People tend to specialize in a few topics, because there’s just not enough time to master everything.
So that is how I see the role of architects in practice: these are the experts who create the ‘building blocks’ for the topics your company specializes in.
Perhaps it is interesting to take some topics that I have discussed earlier on this blog. If you look at my retro programming, you will find that quite a bit of it has the characteristics of research and development. That is, a lot of it is ‘off the beaten path’, and is about things that are not done often, or perhaps have not been done at all before.
The goal is to study these things, and get them under control. Beat them into submission, so to say. Take my music player for example. It started as the following problem:
“Play back VGM files for an SN76489 sound chip on a PC”
You can start with the low-hanging fruit, by just taking simple VGM files with 50 Hz or 60 Hz updates, and focus on reasonably powerful PCs. Another developer had actually developed a VGM player like that, but ran into problems with VGM files taken from certain SEGA games, which used samples:
The problem with VGM files is that each sample is preceded by a delay value, so it doesn’t appear to be a fixed rate. And in fact, the sample could be optimized, so that the rate is indeed not fixed at all. That is, the SN76489 will play a given sample indefinitely. So if your sample data contains two or more samples of the same value, it can be optimized by just playing the first one, and adding the delays. Various VGM tools will optimize the data in this way.
The other guy had trouble getting the samples to play properly at all, even on a faster system. VGM allows for 44.1 kHz data maximum, so the straightforward way would be to just fire a timer interrupt at 44.1 kHz, and perform some internal bookkeeping to handle the VGM data. If your machine is fast enough (fast 386/486 at least), it can work, but it is very bruteforce. Especially when compared to the Sega Master System the game came from. That one only has a Z80 CPU at 4 MHz.
So I thought there was a nice challenge: if a Z80 at 4 MHz can play this, then so should an 8088 at 4.77 MHz. And the machine shouldn’t just be able to play the data by hogging the CPU. It should actually be able to play the data in the ‘background’, so using interrupts.
That is the problem I tried to solve, and as you see, I also drew some diagrams to try and explain the concept at a higher level. Once I had the concept worked out, I could just write the preprocessor and player, and the problem was solved.
I later re-used the same idea for a MIDI player. Since the basic problem of timing and interrupts was already solved, it was relatively easy to just write an alternative preprocessor that interpreted MIDI data instead of VGM data. Likewise, modifying the player for MIDI data instead of SN76489 was also trivial.
And these players also made use of two other problems that had been solved previously. The first is the auto-end-of-interrupt feature of the 8259 chip, which I discussed earlier. Because I solved that problem by creating easy-to-use library functions and macros, it was trivial to add them to any program, such as this player.
The second one is the disk streaming, which I also discussed earlier. Again, since the main logic of using a 64k ringbuffer and firing off 32k reads with DMA in the background was solved, it was relatively easy to add it to a VGM or MIDI player. Which in turn worked around the memory limitations (neither VGM nor MIDI data is very compact, and more complex files can easily go beyond 640k).
So, I think to sum up, here are a few characteristics that apply to a software architect:
- Able to extract requirements and constraints from the stakeholders’ wishes/descriptions
- Able to determine risks and limitations
- Able to translate the problem into a working solution
- Able to find the best/fastest/most optimal/elegant solution
- Able to explain the problem and solution to the various stakeholders at the various levels of abstraction/knowledge required
- Able to explain the solution to other developers so that they can build it
- Able to actually ‘solve’ the problem by creating a library/framework/toolset/etc that is easy to (re)use for other developers
Politics
Here’s another thing I’d like to add to the previous article. I talked about how a software architect would work together with project managers, developers and other departments within the organization. I would like to stress how important it is that you can actually work together. I have been in situations where I may have had the title of architect on paper, and I was expected to be responsible for various things. But the company had a culture where managers decided everything, often even without informing, let alone consulting me.
If you ever find yourself in such a situation, then RUN. The title of architect is completely meaningless if you do not actually have a say in anything. How can you be responsible for the development of software when you have no control over the terms under which that software is to be developed? And of course, managers never understand (or at least won’t admit) that it’s often their decisions that lead to projects not meeting their targets.
For example, if you take some of the things described above, such as getting requirements/constraints and doing risk assessment. These things take time, and time has to be allocated in the life cycle of the project to perform these tasks. If a project manager can just decide that you do not get any time to prepare, and you just have to start developing right away, because they already set a deadline with the client, there’s not much you can do. Except RUN.