Thursday, December 06, 2018

Avoid Global Variables

Global variables make it hard to find out what code broke the system.


Global variables make it convenient to write programs; after all, if you need to access or change x, you just do it. Unfortunately, if x is ever accessed and found to have an inappropriate value, it is difficult to determine which software component is at fault. "Global" implies that anybody could have altered its value incorrectly.

As an alternative, encapsulate important data in its own module, so that anybody who wants to change it or access it must do so by means of that routine. Alternatively, explicitly pass parameters to routines that need specific data. If you find an excessive number of parameters, perhaps your design needs to be reworked.


Reference:
Ledgard, H., Programming Practice, Vol II, Reading, MA: Addison-Wesley, 1987.

Wednesday, December 05, 2018

Avoid Tricks

Obscure programming results in software that takes longer to make and maintain.

Many programmers love to create programs with tricks. These are constructs that perform a function correctly, but in a particularly obscure manner. Typically, they use a side-effect of a function to implement a primary function. Programmers see these as "clever," but, as Allen Macro points out, they "are often merely the stupid use of high intelligence."
    There are many ways to explain why tricks are used so often:
  1. Programmers are extremely intelligent and want to demonstrate that intelligence.
  2. Maintainers, when they finally figure out how the trick works, will not only recognize how smart the original programmer was, but also will realize how smart they themselves are.
  3. Job security.
Bottom line: Show the world how smart you are by avoiding tricky code!


Reference:
Macro, A., Software Engineering: Concepts and Management, Englewood Cliffs, NJ: Prentice-Hall International, 1990.

Tuesday, December 04, 2018

Software Reliability Can Be Achieved Through Redundancy

True software redundancy requires redundant design.

In hardware systems, high reliability or availability (Specify Reliability Specifically) is often achieved through redundancy. Thus, if a system component is expected to exhibit a mean-time-between-failures of x, we can manufacture two or three such components and run them in either:
  1. Parallel. For example, they all do all the work and, when their responses differ, one is turned off with no impact on overall system functionality.
  2. Or cold standby. A backup computer might be powered on only when a hardware failure is detected in the operational computer.
Manufacturing cost is slightly more than doubled. Design cost increases slightly. Reliability increases exponentially.
    In software systems, we cannot use the same approach. If we make two copies of the same software, no increase in reliability will be achieved. In one fails, the other will as well. What can be done, however, is to design (using two different design teams) two versions of the software from the same requirements specification, and deploy them in parallel. Development cost doubles. Reliability increases exponentially. Notice that, in the case of hardware, design increases in cost only slightly, whereas software design cost (the primary cost of software) doubles. Ultrahigh reliability in software is very expensive (High Quality Software Is Possible).


Reference:
Musa, J., et al., Software Reliability, New York: McGraw Hill, 1987.

Monday, December 03, 2018

"Garbage In, Garbage Out" Is Incorrect

When garbage is put into quality software useful responses to fix the garbage should come out.

Many people quote the expression "garbage in, garbage out" as if it were acceptable for software to behave like this. It is not. If a user provides invalid input data, the program should respond with an intelligent message that describes why the input was invalid. If a software component receives invalid data, it should not process it, but instead should return an error code back to the component that transmitted the invalid data. This mindset helps diminish the domino effect caused by software faults and makes it easier to determine error causes by 1) catching the fault early and 2) preventing subsequent data corruption.


Reference:
McConnell, S., Code Complete, Redmond, WA: Microsoft Press, 1993.

Saturday, December 01, 2018

Imposter Syndrome

All fields have some amount of imposter syndrome. It happens in Software Engineering a lot. Constantly changing technologies and changing projects can catch a person off-guard and overwhelm them. Often the problem is only in your head. You actually are doing fine, or would be if you gave yourself a chance. Peter J. Denning wrote an excellent article about this called The Beginner's Creed. The creed is all about learning to be expert beginners so new technologies and projects don't overwhelm us.


Thursday, November 29, 2018

You Can Reuse Without A Big Investment

Salvaging is a tried and true technique for accomplishing software reuse.
When salvaging you got to be the tug that pulls what you need to the surface.

The most effective way to reuse software components is from a repository of crafted, handpicked libraries that were tailored specifically for reuse. However, this requires considerable investment in both time and money. It is possible to reuse in the short term through a technique called salvaging.

Salvaging is asking others in your organization if they have built a software component that does X. You find it, you adapt it, you employ it. This may not be efficient in the long term, but it certainly works now; and then you have no more excuses not to reuse.

To my experience, few organizations are willing to allocate time for the proper care and upkeep of a repository of reusable software components. Salvaging might be your only option. And it gets you talking to your peers on different teams. This communication is like grease that will make future interactions smoother.

Wednesday, November 28, 2018

Know Your Application

Let the details of the application lead the selection of the architecture.

No matter how well the requirements have been written, the selection of optimal architectures and algorithms is very much a function of knowing the unique characteristics of an application. Expected behavior under stress situations, expected frequency of inputs, life-critical nature of response times, likelihood of new hardware, impact of weather on expected system performance, and so on are all application-specific and often demand a specific subset of possible alternative architectures and algorithms.


Reference:
Curtis, B., et al, "A Field Study of the Software Design Process for Large Systems," CACM, November 1988.

Tuesday, November 27, 2018

Store Requirements in a Database

Use a database to facilitate making changes to requirements.

Keep in mind that the follow quote is from 1995. It is still completely relevant.
Requirements are complex and highly volatile. For these reasons, storing them in electronic media, preferably a database, is a good idea. This will facilitate making changes, finding implications of changes, recording attributes of specific requirements, and so on.
      Some of the things you want to store in the database are unique identifier (Separately Number Every Requirement), the text of the requirement, its relationship to other requirements (such as more abstract or more detailed descriptions of the requirement), importance (Prioritize Requirements), expected volatility, pointers to its sources (Record Why Requirements Were Included), applicable product versions (Identify Subsets and Give Every Intermediate Product a Name and Version*), and so on. Ideally, the requirements specification itself is nothing but an organized "dump" of the entire database.
I have used JIRA. There are many tools like it. They can do all of the above, but it is up to the person creating a ticket in JIRA to ensure those things are done. I think they are really important so I'm going to list them again.
  • Create the ticket in a backlog or project that is unique. Do not lump unrelated tickets together. This will result in a "fatlog" - a fat backlog that is difficult to groom and manage.
  • The text of the requirement goes in the "description". The "summary" is not where the requirement should be detailed. Personally, I think systems like JIRA should not allow tickets that have no description to be saved. Engineers should refuse to estimate such tickets and Product Owners who create them should be ashamed.
  • JIRA has a feature to link tickets. Use it. If there is a dependency then utilize the sub-task feature. Make a story that encapsulates both tickets and make them linked sub-tasks. Use the system to track if everything for that requirement is actually done.
  • Order the tickets by importance. There can only be one highest priority and it at the top.
  • Use comments to document the sources/stakeholders for a ticket. Do not use comments to have a discussion about a ticket. Email, call, instance message, etc with the people involved. If you absolutely must use the comments section of a ticket to have a discussion then clean it up later. Delete anything that will mislead people reading the ticket. If you want to save the history then move that stuff into a document and attach it to the ticket with a title that makes it clear that it is for history and it is not the requirement. The actual requirement is in the description.
  • Ensure that you put what product the ticket applies to either in the summary or the description. You might be inclined to think that it is clear by where the ticket sits. For example, the ticket is in the product A backlog. Invariability, someone is going to get confused and try to work that ticket for product C which is really similar to product A. I've also seen people accidentally move a ticket to a different backlog then not be able to figure out where it belonged.
  • If you can't take the issues in a JIRA backlog and print them out in order and call that your software requirements specification (SRS) then your backlog is a mess and you have some work todo.

6 Tips to Make Your Backlog Lean

Monday, November 26, 2018

Self-Destruct TBDs

All TODO and TBD notes should have a specific person responsible for resolving them.

A software requirements specification (SRS) with a TODO or TBD (To Be Determined) note is obviously not complete. There may be good reasons for approving and starting work on a project with a TBDs in the specification. This is particularly true for requirements whose precision are not critical to fundamental design decisions.

When you create a TBD, be sure to footnote it with a "self-destruction note," that is, specify who will resolve the TBD and by when.


Reference:
IEEE, ANSI/IEEE Guide to Software Requirements Specifications, IEEE Computer Society Press, Washington, DC, 1994.

Saturday, November 24, 2018

Specify When Environment Violates "Acceptable" Behavior

Know what to do when things go wrong.

Requirements specifications often define characteristics of the system's environment. This information is used in making intelligent design decisions. It also often implies that the developer is contractually obligated to accommodate such characteristics. What happens after deployment when the environment exceeds the specified limits?

Suppose the requirements for an air traffic controller system specify that the system shall handle up to 100 aircraft in a sector simultaneously. They system is built and correctly satisfies this requirement. Three years later 101 aircraft accidentally enter a sector. What should the software do? The possibilities are:
  1. Print an error message.
  2. Crash.
  3. Ignore the 101st aircraft.
  4. Process all 101 aircraft but perhaps not satisfy some other timing constraint (such as how often the screen is updated).
Obviously, options 1, 2, and 3 are unacceptable. Yet they are valid system responses as (not) stated in the requirements. The right solution is to explicitly state in the software requirements specification (SRS) the expected system response when the environment exceeds any of the constraints defined for it.


Reference:
Davis, A., Software Requirements: Objects, Functions, and States, Prentice Hall, Englewood Cliffs, 1993.