DOC PREVIEW
UE CS 215 - CS 215 ­ Fundamentals of Programming II

This preview shows page 1-2 out of 6 pages.

Save
View full document
View full document
Premium Document
Do you want full access? Go Premium and unlock all 6 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 6 pages.
Access to all documents
Download any document
Ad free experience
Premium Document
Do you want full access? Go Premium and unlock all 6 pages.
Access to all documents
Download any document
Ad free experience

Unformatted text preview:

CS 215 - Fundamentals of Programming IISpring 2010 - Tips on Managing Programming ComplexityAs programming projects become more complex, we need techniques for making projects manageable. In general, the probability that we can write all the code of the project at once and expect it to just work is very low. And when things do not work, it becomes increasingly difficult to isolate the problem, and in fact, it may be the case that the error is in the interaction of two or more parts of the project that seem to work fine individually. This handout is a work-in-progress intended to give the reader some basic tips on managing the complexity of a large programming project. It is neither exemplary nor exhaustive, but if you follow the tips, it should make managing any project easier. 0. Serious analysis and design up-front reduces implementation time This may seem obvious, but it is the most important tip. Resist the urge to write any code until you have thought about what you are trying to do and how to get there. The more you know where you are going, the less time it will take to get there. The goal of this step is to break down the problem into small, well-defined pieces. An exception to this guideline is sometimes you do want to write some prototype code just to see how something works. That's fine as long as you expect to “discard” the actual code and do not try to evolve it into your entire project without serious thought as to how it fits in. 1. Implement the pieces of your design a few at a time This also may seem obvious. Resist the urge to write all the code at once, and then try to debug it. Solve the pieces a few at a time, making sure that they work by writing one or more driver programs that test the pieces individually. Start with the foundation pieces, then move on to the more refined pieces. Always test the interactions between what you have already written and the new piece by rerunning your previous tests. For example, when writing a new class, start with the constructors, so that you can build objects, then the accessors and output operations that let you see what you have built. Write a driver program that uses just these operations. If the project requires more than one class, start with the simpler one. Sometimes it is advantageous to write a skeleton of a function without any of the actual implementation. That is, you write the prototype and header of the function, but only a minimal body, usually just a message saying the function isn't implemented, yet, and/or returning some default value. These skeleton functions are called stubs and should be used whenever you know you want a particular function, but want to defer actually implementing it until a later time. This allows you to compile and run a program that uses the function, though of course, the results will not be valid, allowing you to see if the other parts of your program work. 2. Debugging statements should contain real information A debugging message such as “Entering operator=” or “operator+ : rhs operand is empty” is much more informative than messages like “Got here” or “Here 2”. If you are going to write debugging statements, they might as well say something useful. One way to manage these statements is to use debug flags and a PrintDebug function: 02/23/2010 Page 1 of 6const bool DBG_PHASE1 = false; const bool DBG_PHASE2 = true; void PrintDebug (bool debug, string message) { if (debug) cerr << message << endl; } // end PrintDebugThe PrintDebug function just prints a message if debugging is “on” (represented by the true value) during the call. The flags are used to turn on and off groups of debugging messages. (Otherwise, you would have to find each one and change the call argument from true to false or vice versa.) For example, a default constructor body might have: PrintDebug (DBG_PHASE1, "Entering default constructor"); // Statements to create default object PrintDebug (DBG_PHASE1, "Exitting default constructor");Another tip is to “indent” the debugging messages if they are inside nested control structures. For example, PrintDebug (DBG_PHASE2, "Entering operator+"); : if (rightPolyPtr == 0) { PrintDebug (DBG_PHASE2, " operator+: rhs operand is done"); : }Now when the program runs, the debugging statements line up as: Entering operator+ operator+: rhs operand is doneand you can see the control structure in the output. When you are finished with your project, you can set all of the debugging flags to false. A good optimizing compiler should be able to detect that the conditions will be false and that the function will not have any other code executed and optimize away the function calls and perhaps the entire function itself. Later, if there is a newly-discovered problem, or you want to make an enhancement, you can turn the debugging messages back on easily. 3. Start with the simplest test cases: expected and boundaries This also may seem obvious, but resist the urge to use a complex test case the first time you run your program. Instead start with the simplest expected test case that will demonstrate the use of the piece you are working on. Once that test passes, go onto to the next simplest test case, etc. 02/23/2010 Page 2 of 6Generally, the number of interesting test cases can be reduced to the phrase “expected, 0/empty, 1, n/full.” For example, this means that one should test for the case of expected input, no input, and one input. In some cases, there will also be a maximum size input that needs to be tested. A concrete example is inserting into a doubly-linked circular list. The algorithm is different for lists of 0, 1, and many elements, so you should test for each case. 4. If things get too confusing, start over Sometimes the right thing to do when you cannot figure out where to start debugging is to just start over writing the program. Usually this happens after you have made a major changes to the design of the project and have forgotten to propagate the changes through all of the existent code. Do this a few times, and you are likely to forget which constructs reflect the latest change and which ones still need to be changed. Throw in some old comments, and you have a mess. Although, it may seem like a “waste” to discard the work, it really is not. By having written the discarded code, you have figured out what you really want to do. So when you start


View Full Document

UE CS 215 - CS 215 ­ Fundamentals of Programming II

Documents in this Course
Lecture 4

Lecture 4

14 pages

Lecture 5

Lecture 5

18 pages

Lecture 6

Lecture 6

17 pages

Lecture 7

Lecture 7

28 pages

Lecture 1

Lecture 1

16 pages

Lecture 5

Lecture 5

15 pages

Lecture 7

Lecture 7

28 pages

Load more
Download CS 215 ­ Fundamentals of Programming II
Our administrator received your request to download this document. We will send you the file to your email shortly.
Loading Unlocking...
Login

Join to view CS 215 ­ Fundamentals of Programming II and access 3M+ class-specific study document.

or
We will never post anything without your permission.
Don't have an account?
Sign Up

Join to view CS 215 ­ Fundamentals of Programming II 2 2 and access 3M+ class-specific study document.

or

By creating an account you agree to our Privacy Policy and Terms Of Use

Already a member?