Since Toolsets may be used in hundreds of applications, and Frameworks are very large in size, those two categories are the most intolerant of defects, hence must have the lowest defect rates. Applications and Frameworks also tend to be very large in size, necessitating even lower defect rates. Defect prevention quickly becomes more critical than defect detection.

Coding in the Big City

On a country road, I can probably get away without looking before I cross the road (my brother always got away with it, though we sometimes heard the squeal of brakes on the road).

However, in the Big City I’ll likely get flattened!

In the big city, requirements change, customers find bugs, schedules get shifted, team members have different interpretations of the requirements, and new requirements are added long after software deployment.

Moral: design and coding practices that may be adequate for end-user software can get you flattened when writing applications, toolkits, or frameworks!

It is common for C programmers to use bit flags for error bits. A single unsigned integer gives 32 possible error bits. In a safety critical application, the senior developers had used a 32-bit unsigned integer in just this fashion. However, a few months into the project they reached the 33rd critical error that had to be tracked. Their solution: was to add a second error variable.

They had to add the second error variable in *every* location where they checked for errors. There were over 50 such locations. They forgot two. The result was a safety related defect that resulted in the recall of medical device software.

Had they instead used an error object, they could have changed the internal implementation to accommodate additional error flags without impacting the rest of the code.

Declarative. Lines of code constitute rules that are interpreted by an engine. Program flow is determined by the engine. Some example languages are: Prolog, LISP, PALASM, VHDL, SQL.

Another way of categorizing langauges is by the distance from the hardware:

First Generation - uses the native machine code of the processor. Programmed in raw 1's and 0's. Code only runs on that processor.

Second Generation - uses mnemonic codes to represent the native machine code. For example, instead of writing a line of code that looks like 1101111000010110, you would write a line like:
move a, c.
In a second generation langauge, one line of code generates one line of machine code. Code only runs on that processor. Some example langauges are Assembly, PL/M, and PALASM.

Third Generation - uses more abstract concepts, like A = B + C. Each line of code generates several lines of machine code. In some cases, the code only runs on that processor; however, languages like Java and JavaScript can run on different types of processors. Some example languages are: C/C++, Basic, Visual Basic, Pascal, SmallTalk, Java, and Fortran.

Fourth Generation - abstracts the programmer from the procedural nature of the code and focuses on the business rules. Languages tend to become more declarative. Program can run on any machine that has an engine for the language. Some example langauges are: SQL, LISP, Prolog, VHDL.