![]() |
.. (לתיקייה המכילה) | |
Below are a few reminders of common coding errors and tips on how to avoid them, with examples relevant to the wet assignments.
Code Duplication | |
Rewriting (or copy-pasting) large code segments which are logically identical throughout your code can (and will!) force you to invest more time in debugging or changing your code in general. Use tools you've learned in order to prevent code duplication, such as adding additional functions, template functions or classes etc. Merge identical code segments Examples: Writing many tree classes that perform the same logical functions. (In this particular case, template classes would have prevented the unnecessary work). |
"Magic Numbers" | |
Use of numeric constants throughout your code will make it harder for you to remember their meaning, and will prove problematic when these constants will have to be changed throughout the code (due to logical changes or finding of errors). Define constants and name them (using #define, enum, or const) |
Long Functions | |
Writing functions that span hundreds of lines of code, will make it harder for you to debug your code and follow its logic when verifying/modifying it. Write shorter functions, by removing redundancy, simplifying your code and writing functions to replace well-defined logical portions of long functions |
Poor Modularity | |
Writing a class without the functionality needed of it will force you to re-write said functionality over and over again, every time it is needed (which brings us back to the note concerning long functions and code duplication). Concentrate the necessary functionality of your classes within the classes themselves Examples: Writing code to find/add/remove from data structures in classes containing them. Writing functions for destroying a data structure in a containing class. |
The excercise is very big and complicated, how do I begin? | |
First, read the excercise thoroughly, make sure you understand the entities involved in the story and write them down. After you do that, try to solve the question theoretically, using only pen and paper, do some sketches and make sure you understand how the entities are represented using the required data structures and how they are connected to each other. After you have the layout of the data-structure, write the algorithms which give the functionality that you have to implement in the excercise and make sure you understand and can explain why their time/space complexity is satisfying the excercise's requirements. In addition, write down all the data-strcture's invariants (for example - AVL's invariant is the |BF(v)|<=1 for all nodes in the tree), make sure the algorithms you devise keep the invariants. After you solve the excercise theoretically write for each entity the required attributes (which will be used for in your code) you need to maintain and define it and which methods need to be implemented for each entity. This is the most important part of the excercise, DO NOT begin programming until you are 100% sure you have a right solution in your hand. (unless you want to program twice the same excercise). |
Tips for debugging and writing code with less bugs? | |
One can simply debug his program by running it step-by-step in his favorite IDE, however some more efficient techniques exist: 1) Use assert(...) to assert your implementation holds certain properties (include assert.h). When debugging, make sure to use the g++ flag -DNDEBUG to remove all the asserts from your code (since checking some properties of your data structure in O(N) is not allowed in an algorithm which has to for example in O(log(N))). 2) We recommend to debug the code while writing it, meaning that once you've finished writing a certain module, make sure it works on its own before integrating it with other modules. For further reading you can read about the test-driven-development (TDD) methology on the internet. 3) Linux developers can use the ddd debugger (or emacs). 4) For resource leak bugs you can use valgrind. 5) If you want to compare your data structure to an already correct data structure you can give the same API for that data structure as a parallel STL implementation gives, so if you implement, for example a tree, you can write the following lines: typedef MyTree Tree; //typedef STLTree tree; So once want to check your solution you run a test once with the second line commented, and once with the first line and compare the outputs. 6) To debug more easily your solution it is strongly recommended that you implement your data structures independently from your excercise. 7) You are encouraged to write simpler code which runs in 5*n time rather than a complicated on which runs in 0.5*n times. 8) Try to keep only one pointer to each object you allocate to prevent dangling references and/or resource leak. |