Software Documentation

Software Documentation

This is an area of Software Development that has always been a challenge. The documentation falls into six general categories:


  • Software Design Documentation
  • Software Testing and Test Results
  • Software Implementation Details
  • Software Change Management
  • User Documentation
  • Coding Standards


Each of these has its own specific issues.


There are formal documentation standards including IEEE 829 for Software Test Documentation and IEEE 830 for Software Requirements Specification and IEEE 1016 for Software Design Description. Even if you are not using these standards, it is worth reading them and understanding the ideas and methods they teach. These are well thought out standards.


Software Design Documentation

We work for a wide range of clients and some have very strict criteria while others leave it entirely up to us. The strictest criteria we work with are biomedical, automotive or transport clients. These require upfront definitions of everything including the Software Test Methodology and the specific tests to be done and the pass fail criteria. And of course, every change request up-issues every affected document. So that has to be budgeted for.


Software Design balances the project priorities

Software Design

For clients without specific requirements, we use the following methods:


  • Define the requirements and how they will be tested
  • State all known constraints
  • Describe the operating system
  • Show the Functional Decomposition into modules
  • Show the module communication
  • Use diagrams to show all State Machines
  • Document tests and test results


For larger projects, we might choose to have separate requirements and test documents but we always align the numbering so the test for a requirement has the same number as the requirement. For instance, if requirement 2.3.1 was that the system accommodate BAUD rates from 9600 to 115200, then test 2.3.1 would be to set and confirm the system operated with each of the BAUD rates.


This helps with both ensuring requirements are all tested and implemented, and that changes can easily identify which tests need review when a requirement is changed. Very large projects would use a Requirements Allocation Matrix where the requirement is cross-referenced with the modules that implement it.


Functional Decomposition

Functional Decomposition is the process of breaking the project up into specific modules and allocating requirements and functions to them. Since we do the whole gamut of Electronics Design and Embedded Software Development, this includes deciding how many processors we will use and how we break up requirements between them.


Functional Decomposition

Functional Decomposition

The intent is to take the complex and break it down into simpler pieces until they are simple enough to implement as functions in their own right.


Software Testing

For Software Testing the process is conceptually simple:


  • What is tested – which requirement are we meeting
  • How is it tested – the test protocol
  • What results are recorded – the test records
  • What the pass criteria is – the test acceptance criteria


This is usually best handled with tables except for user interface interactions which might use recordings as well as written test results documentation.


Software Implementation Details

This usually consists of the source code documentation since the Software Design has already been documented. Many modern toolsets include source browsing and database tools, but these require the end client to have the same toolsets. So we also add Source Code Documentation tags supported by Doxygen which allows a toolset and platform independent set of documentation to be created. If you haven’t used it, what you get is a website with everything hyper-linked. You can also create hyper-linked PDFs but we usually stay with the html.


Doxygen Source Code Documentation


You can create diagrams, caller graphs, callee graphs and state machine descriptions using the Graphviz tool which is supported by Doxygen.


Doxygen Call Graph

Doxygen Call Graph

Our gratitude goes to Dimitri Van Heesch for creating and maintaining Doxygen which you can support by donation.


Software Change Management

So you have a software project that passes all its tests and its out there and working. Now you, or your client, want to change something!


The last thing we want to do is break something while trying to make it better. So when changes are needed, they have to be analysed. Things to consider are:


  • Which requirements are affected by the change?
  • How risky is the change?
  • Who need to approve of the change?
  • Are there any new requirements or new tests required?
  • Will field testing be necessary?
  • Are there regulatory approvals affected?


So trivial changes like updating the wording on a form are usually low risk and don’t require a lot of risk management of multiple levels of signoff.


A more significant change like altering the wheel pressure balancing algorithm in a ABS braking system gets the maximum level of attention.


User Documentation

If the product has a User Interface or supports user interaction, then this also needs to be documented. This documentation is usually written for the user to read and is intended to assist the user.


The format of the documentation depends on the product. It could be online help, tool tips, printed manual, soft manual, on screen or printed on the product itself. One method of User Documentation assessment is with randomly selected people who could be potential users. This is to identify concepts understood by the development team by not either generally understood or else not adequately explained in the documentation.


Coding Standards

This will be covered in more detail in another blog post. Because a range of programmers will work on any significant project, it is well worth defining how code is to be written. This consistency will lead to easier to read and maintain code.


For instance, Embedded C bracketing uses to follow the UNIX convention which goes like this:


for(length = MIN; length <= MAX; length++){


This had advantages in the days when VDU screen space and Teletype or Lineprinter paper space was at a premium, but it makes sense to make the indenting easier to understand by doing it this way:


for(length = MIN; length <= MAX; length++)


Regardless of the type of project, easy to read and understand Software Documentation will reduce maintenance costs is essential for larger teams to be able to deliver a working project.


Successful Endeavours specialise in Electronics Design and Embedded Software Development. Ray Keefe has developed market leading electronics products in Australia for nearly 30 years. This post is Copyright © 2012 Successful Endeavours Pty Ltd

Reducing Electronics and Embedded Software Product Development Costs

First some basic statistics that made me think about this issue a bit more:

  • Software typically consumes 80% of the development budget. Digital Avionics Handbook and
  • 80% of software projects are unsuccessful IBM


So working from the Pareto Principle it is clear that product development success and cost can be most improved by addressing the Software Development component. In my recent post on Reducing Electronics Manufacturing Parts Cost I argued that increasing the software component can reduce the hardware costs. Which is a great idea as long as it doesn’t introduce an even more expensive problem.


I agree with Jack Ganssle in his article looking at tools where he points out that software quality tools are often not budgeted for yet will find many classes of defect quickly and at a significantly lower cost than the test and debugging effort required to find them after integration with the rest of the project. Or put another way, the cheapest way to get rid of bugs is not to introduce them in the first place – Lean Coding.


Since we mainly develop in C and C++, this is what we do to ensure we minimise software development cost and overruns:


Static analysis and code reviews

We use static analysis and code quality tools such as PC-Lint and RSM and integrate them into our editors and IDEs so we can run the tests are part of our build or at the very least with a single click covering either the current file or the current project. These tools find flaws you are hard pressed to identify by visual inspection and I believe they pay for themselves within a month of purchasing them. They can also enforce coding standards. Another great benefit is that when you do a code walk through and review, you are not looking for these classes of faults explicitly because you know the toolset will find them for you. So the first thing you do is run the tests and focus on anything found there.


Code reviews save money. Every issue identified in a code review is an issue you don’t have to debug later on. And another person is going to look at your code without the same assumptions you would so they will see the things you miss. It just makes sense to do it. Software debugging is more expensive than coding so not bugging in the first place is good budget management.


Unit testing

Next, we unit test. A huge benefit of this is that you have to think about test and it makes you think about error handling in the design phase. Many problems in implementing embedded systems come from not handling errors consistently. Sometimes they aren’t handled at all! Someone else once suggested that software developers were the most optimistic people on the market – you can tell this is true by looking at how they handle exceptions! I’m not sure who said it so if you know then post a comment and I’ll credit them and provide a link too if you have one.


Integration testing

Integration testing itself does not have to be overly complex. You want to know that things work and it is often easier to write a cut down system to manage the test process. This way you are proving that each subsystem is present and correct before doing the full scale system test. This is an area that often gets overcomplicated. Don;t try and do more here than you have to.


Oh, and by the way, just because something builds don’t mean it passes the integration test. Some things to cover are:

  • software manifest – do I have the right version of each module?
  • data flow – do the higher level calls get at the right data lower down?
  • exceptions – do error returns get passed back?
  • exceptions again – if you raise exceptions, do they get acted on?
  • communications – does it communicate?
  • IO – are they mapped to the right pins and peripherals?


For some systems or subsystems we write fully fledged PC mocks around the code and ensure it handles all the parameter and error cases correctly and that all the functions are correctly implemented. This is a form of integration testing that proves the software component of the system is doing what it is meant to but goes a lot further to fully excercise part of it. And since 80% of the problems come from software this is a very effective way of reducing bugs and difficult to track down system defects that are expensive on time and resources to cover in real time operating tests.


To do this, you have to abstract the interface so the code can run in the embedded version or the PC version without any changes. This is easy to do if you think about it in advance.


One word of caution; the PC has a lot more resources and clock speed available compared to a smaller embedded system so this is not a substitue for testing on the real hardware to ensure execution latency is acceptable.


And for the purposes of this post, the PC could just as easily be a Linux or Mac system. The point is to use the higher level system to efficiently and fully test the embedded software module so you save time and money later on in the project. And let’s face it, who like to be under unnecessary pressure at the back end of an embedded software project?


System testing

If you think in advance about how to most easily implement the system testing then you can save a lot here as well. We put effort into deciding how the do the test process at the architecture design phase so that we have the data flow required to actually do the test. This can be as simple as having some extra parameters or calls available to be able to inspect the state of the system and the communications facilities to get at this data. Where possible 100% parameter range testing and 100% code coverage testing is very desirable. One thing this means is that you had better think about how you will create each error condition that must be handled!


Low Cost Software Development

Low Cost Electronics Manufacture relies on Low Cost Software Development. So make it a priority. The Pareto Principle says that it is the most important thing to get right.


Ray Keefe has been developing high quality and market leading electronics products in Australia for nearly 30 years. For more information go to his LinkedIn profile. This post is Copyright © Successful Endeavours Pty Ltd.