Reading Assignment: All of Programming Chapter 13 Programming in the Large
One of the key techniques for designing any large system is abstraction. The interface of something is what it does, while the implementation is how it does.
The “things” in this limitation are in terms of pieces of information with semantic meaning to the person thinking about them. Note that being able to think about a function is important in a variety of contexts. If a function’s complexity exceeds your cognitive capacity, it becomes very difficult to write. You may need to review your code several years later. Abstracting code out into functions provide a way to wrap the entire behavior up into one logically meaningful thing–the resulting function has a well defined task, and you can think about it in terms of what its interface rather than its implementation.
Abstraction works hierachically-we can combine the samllest “building blocks” of our system into larger logical units, and repeat this process until we have a large, complex system.
Designing software with hierachical abstraction can primarily happen in two ways: bottom-up or top-down. In a bottom-up design, you start with the samllest building blocks first, and build successively larger components from them. This approach leads itself well to incremental testing(build a piece, test it, build a piece, test it…). However, the downside is that you have to be sure that you are building the right blocks, and that they all fit together in the end. The other design philosophy is top-down. In top-down, you start by designing the highest-level algorithm, and determine what other functions you need in support of it. You then proceed to design these functions, until you reach small enough functions that you do not need to abstract out any more pieces. The downside to top-down design can arise in testing. If you try to write the whole thing, then test it, you are asking for trouble. However, if you implement your algorithm in a top-down fashion, you may have high-level algorithms which rely on lower-level pieces that do not exist. The problem can be overcome in a couple of ways.
Many aspects of a code’s design and implementation contribute to its readability-or lack thereof.
A general rule of thumb is that your function should fit comfortably into one screen-that is, you should be able to read the entire ting all at once without scrolling. (Traditionally, 80 columns by 24 lines was the standard size of a terminal. With larger monitors these days, 100 columns and 32 lines is imminently reasonable, but do not be surprised if you work in an organization with an 80x24 rule.)
A good rule of thumb here is that the length of a variable’s name should be proportional to the size of its scope, and the complexity of its use.
Some people like naming conventions. One is placing a
_t suffix on the type name. Another is writing the names of constants in all capitals. Some programmers like the “Hungarian Notation” sheme, where variable names are prefixed with a sequence of letters indicating their types(e.g.
chInput starts with a “ch” indicating its type is
char, and while
iLenth starts with an
i indicating its type is
Another set of conventions arise in how you “glue together” multiple words with underscores
num_letter_skipped. The other is to capitalize the first letter of words other than the first.
One common rule is that code should be indented to reflect the block structure. Another is that one should generally place a new line at the end of a statement, so that consecutive statements appear on different lines. We strongly prefer the so-called “Java” style.
Good documentation provides insights into the algorithm being used, explains why things that may seem surprising are correct, and generally allows the reader to understand how and why the code works the way it does.
Documentation Large Scale Design. As you design larger programs, you will have multiple pieces that fit together. Describe how they fit together. What are the interfaces between modules? What are the invariants of the whole system?
Describe Each Component.
Do Not Comment The Obvious.
Explain The Unexpected.
Revision and control system is important, like Git, Subversion, or Mercurial.
Team can accomplish more in the same time than any individual can. One nice way to work in partnerships is pair programming. In pair programming, two programmers share a computer with one “driving” and the other “navigating”. The driver controls the keyboard and actually wirtes the code. Meanwhile, the navigator watches the code being written and thinks about what is happening. The navigator is responsible for checking for problems with code-whether they are just local mistacks, or failure to respect global invariants. The programmers may trade roles whenever they feel it is appropriate.
As the size of our progrmming problems continues to grow, so does the need to break the task down into manageable pieces. Writing samll pieces of code, then testing them is the only way to make solid progress. One important way to split larger problems into smaller problems is to start with a minimal set of features, then add new features once at a time.