what order the parameters should occur. Like using C pointers only in a very restricted manner - to pass arguments and to reference entire records of internal or database data. Like being consistent across all of our software, especially with coding standards, and
training new employees on the design rules in such a way that they could
understand how each rule helped. Like establishing good naming standards that helped code readability rather than hindered it. Like instituting peer code reviews with a focus on design rules and refactoring as part of those reviews.
Some might be surprised that on the C-language side of things, we actually
significantly restricted the use of the language. C is too flexible. we replaced the "case ... break" with a "_case" macro, ensuring the previous case was ended before the
new case. We disallowed loops where the conditions were at the end of the loop rather than at the beginning - simply because it makes the code harder to read. We severely restricted how pointers could be used. Of course we eliminated "goto" and statement labels (other than for "switch" statements). We eliminated nested functions, simplifying
scoping rules and increasing re-use. We assumed that #define's would eventually be replaced with real variables and so named the defined variables contrary to the usual UPPER CASE convention. We replaced C-Strings with our own descriptor-based strings so that strings would not have to be copied to point to sub-strings. And so forth - whatever we could do to reduce errors and improve readability and simplicity.
We introduced some basic guidelines. Simplicity is more important that optimization. Keep functions under 50 lines generally. Mixed Case for Global Names, including Global
Variables (with guidelines) and Function and Type Names - no abbreviations here, unless they were well defined acronyms (e.g. DB), and lower case for local names, including field names and local variables. As local names had full context within a few
lines, shorter names were recommended to make the code more concise and hence
easier to read. Common local variables, such as str for a general String, pos for position within a string, i, j, k for normal arbitrary loop index values, n and count for counts. We focused more on good names for boolean locals. And we made sure that the names
chosen made the code (e.g. if statement) more readable. This is especially important with booleans, arrays, and function names.
We focused on constant code refactoring, because software architecture was
everything. Copy and paste was replaced with factoring and this not only kept the code minimal, but eliminated the multiplication of bugs with each copy and paste operation. It further allowed us to improve the factored code rather than having to try to track down all of the copy/paste locations.
Getting the Requirements Right
Neuma's CM product evolved over a period of about 20 years (so far). So how did we get the requirements right, or did we? Well first of all, the wealth of large project CM experience helped. We knew, for example, that change packages (aka "updates") had to be at the center of any solution. We also knew the value of seamlessly integrating applications and the derrived benefits. But it was still not easy. For one thing, GUIs were rare and evolving in their infancy 20 years back. Networking dealt with connecting mainframes together (except in the Unix world), and not users. And our CM tool experience was based on fixed company requirements, once for an IBM mainframe supporting hundreds of users, and once for a small network of DEC Vax mainframes supporting a couple hundred users. Keeping the command line interface simple was important. So was the architecture of each language we were using, in both cases proprietary.
The focused in-house requirements gave us a tremendous blind side, especially
because Windows wasn't mainstream for development, and Unix was