ì Design, Modularity & Testing 15#441%Recita,on%3%M.Tarek%Abdella,f%Carnegie%Mellon%University%%Design,%Modularity%&%Tes,ng%Let's%First%Talk%About%Checkpoint%2%ì Available%under%"Assignments”%ì What%you%have:%ì Handle%concurrent(connec)ons%%ì Avoid(blocking,%one%client%should%not%be%able%to%stall%server%by%sending%a%par,al%command.%ì What%you%need%to%do:%ì Handle%Nick,%User,%Join,%List,%and%Part.%ì Follow%the%RFC%to%know%the%reply%format.%%Recitation 3 ì Design Principles ì Guidelines for Projects ì Testing ì Q&A - Project 1/HW 1….Thinking about Design ì How do you start thinking about how a program should work? ì Data-centric programs: ì What data does it operate on? ì How does it store it? ì Examples? ì Protocol-centric programs ì How they interact with the rest of the world ì (Maybe "Interface-centric") ì (Not exclusive! Think about IRC server)Design Principles ì Goal: once again, pain management ì Be able to develop independently ì Avoid the big brick end-of-semester wall ì Stay motivatedP1: Don't Repeat Yourself ì Aka "DRY" ì Like factoring out common terms… ì If you're copy/pasting code or writing "similar feeling" code, perhaps it should be extracted into its own chunk. ì Small set of orthogonal interfaces to modulesExercise 1 int send_usr_join_msg(char *ch_name, char *msg){ … struct user *u; for (u = userlist; u != NULL; u = u->next) { if (!strcmp(u->username, uname) … int send_usr_quit_msg(char *ch_name, char *msg){ … struct user *u; for (u = userlist; u != NULL; u = u->next) { if (!strcmp(u->username, uname) …Exercise 1 Contd.. Consider factoring into: struct user *find_user(char *username) ì Hides detail that users are in a list ì Could re-implement as hash lookup if bottleneck ì Reduces size of code / duplication / bug count ì Code is more self-explanatory ("find_user" obvious), easier to read, easier to testP2: Hide Unnecessary Details ì Aka, "write shy code" ì Doesn't expose itself to others ì Doesn't stare at others' secrets ì Doesn't have too many close friends ì Benefit: ì Can change those details later without worrying about who cares about themExercise 2 ì int send_message_to_user( struct user *u, char *message) ì int send_message_to_user( int user_num, int user_sock, char *message)P3: Keep it Simple ì We covered in previous recitation, but ì Don't prematurely optimize ì Even in "optimization contest", program speed is rarely a bottleneck ì Robustness is worth more points than speed! ì Don't add unnecessary features ì (Perhaps less pertinent in 441)P3.1: Make a few bits good ì Some components you'll use again ì Lists, containers, algorithms, etc. ì Spend the time to make these a bit more reusable ì Spend 20% more time on component during project 1 ì Save 80% time on project 2…P4: Be consistent ì Naming, style, etc. ì Doesn't matter too much what you choose ì But choose some way and stick to it ì printf(str, args) fprintf(file, str, args)!ì bcopy(src, dst, len) memcpy(dst, src, len) ì Resources: Free where you allocate ì Consistency helps avoid memory leaksExercise 3 Void Usr_function() { char *src = "15441"; char *dst; strcpy(src,dst); …… free(dst); } Void strcpy(char * src, char *dst) { dst = malloc(strlen(src)); While((*dst = *src) != '\0) { dst++; src++; } } What is Wrong with this program ??Exercise 3 Contd.. Void Usr_function() { char *src = "15441"; char *dst = malloc(strlen(src)); strcpy(src,dst); …… free(dst); } Void strcpy(char * src, char *dst) { While((*dst = *src) != '\0') { dst++; src++; } } Avoid using strcpy, strlen, sprintf,…..instead use safer version strncpy(), strnlen(), snprintf()….#1 Error handling ì Detect at low level, handle high ì Bad: malloc() { … if (NULL) abort(); } ì Appropriate action depends on program ì Be consistent in return codes and consistent about who handles errors#2 Incremental Happiness ì Not going to write a program in one sitting ì Cycle to go for: ì Write a bit ì Compile; fix compilation errors ì Test run; fix bugs found in testing ì Implies frequent points of "kinda-working-ness"#3 Development Chunks ì Identify building blocks (structures, algos) ì Classical modules with clear functions ì Should be able to implement some with rough sketch of program design ì Identify "feature" milestones ì Pare down to bare minimum and go from there ì Try to identify points where testable ì Helps keep momentum up! ì Examples from IRC server?Testability ì Test at all levels ì Recall goal: reduced pain! ì Bugs easiest to find/correct early and in small scope. Ergo: ì Unit tests only test component (easier to locate) ì Early tests get code while fresh in mind ì Write tests concurrently with code. Or before! ì Also need to test higher level functions ì Scripting languages work well here441 Testability ì Unit test examples: ì Your hash, list, etc., classes ì Command parser ì Routing table insert/lookup/etc. ì Others?Bigger tests ì More structured test framework early ì "Connect" test (does it listen?) ì Alternate port # test (cmd line + listen) ì …Testing Mindset ì Much like security: Be Adversarial ì Your code is the enemy. Break it! ì Goal of testing is not to quickly say "phew, it passes test 1, it must work!" ì It's to ensure that 5 days later, you don't spend 5 hours tracking down a bug in it ì Think about the code and then write tests that exercise it. Hit border cases.Testing a Hash Table ì Insert an item and retrieve it ì Why? ì Insert two items and retrieve both ì Why? [help me fill in this list!] Note ordering: Simple to complex…Design & Debugging ì Covering more next week, but… ì Strongly, strongly encourage people to use
View Full Document