15-213/14-513/15-513 Intro to Computer Systems: Code Style

Just as important as the functionality of your code is your code's readability to others. Therefore, in 15-213/15-513 (and other CS/ECE courses you will take), we will be paying close attention to your coding style and taking it into consideration when assigning grades.

Each semester the question of "What do you mean by 'good style'?" comes up. The course staff has created this document to try and answer that question. The most basic requirement is a consistent and logical style that makes the purpose of your code clear to the reader. We expect you to pick something that is readable and makes sense, and then stick to that through an entire project. The key points we will be looking for are:

SOME QUICK THINGS TO REMEMBER:

  • You should have no magic numbers in your code
  • Keep naming consistent throughout the document. Usually the two naming conventions are
    • CamelCase
    • snake_case
  • Variable names and function names should not be too long but still describe what they are being used for
  • Include proper file and function headers for all files and all functions
  • Comment any part of your code that you think may be difficult for a reader to understand on their own (like if you are using a tricky formula or some shortcut to complete something)
  • Other than lines that are involved with these parts of your code, you generally don't need to have many line-specific comments.
  • Remove all dead code and print statements you use for print statements before your final submission since it makes your code more cluttered.
  • Indent your code to make it easier to read and understand the control flow
  • Indent within functions, if…else, switch statements
  • Keep formatting consistent when dealing with functions and other statements (like how you place your curly brackets within your functions)

MAGIC NUMBERS:

  • Magic numbers are numbers in your code that have more meaning than simply their own values.
  • For example, if you are reading data into a buffer by doing "fgets(stdin, buf, 256)", 256 is a "magic number" because it represents the length of your buffer. On the other hand, if you were counting by even numbers by doing "for (int i = 0; i < MAX; i += 2)", 2 is not a magic number, because it simply means that you are counting by 2s.
  • You should use #define or const globals to clarify the meaning of magic numbers. In the above example, doing "#define BUFLEN 256" and then use the "BUFLEN" constant in both the declaration of "buf" and the call to "fgets".

HEADERS:

Remember that the purpose of a header is to provide the reader with enough information to know what your code does. It doesn't need to be very detailed but it should have enough information such that if they were to implement their own version based on your header, it would be similar. Here are some questions to guide you through writing your file headers (add more info if you want - this is just a starting point)

  • What is the purpose of what you are building? For example, in cache lab, maybe talk a bit - a few sentences - about what a cache is, what does it mean to load/store, what are dirty bits?
  • How are you building it? So discuss any data structures or specific implementation details like for example in cache lab, you might have used some type of array based structure to represent your cache but because this can differ between implementations, describe a bit about how you structured your array.
  • What were some design decisions? This sort of goes hand in hand with "how are you building it" so you can combine the two but it's important to include things that might be unique to your code. For example, in cache lab, people use different eviction policies so discussing your LRU policy and how you have implemented your LRU (singly linked list, queue, etc) is important.
  • Anything else you think the reader needs to know to understand your code without actually reading through all of it.
  • Think of this section as a summary for your code.

FUNCTION HEADERS:

The purpose of these is to make sure your reader can understand what your function does without having to actually read through the function code (a mini file header specific to your function). Usually the format of these is as such

/*
* @brief - explain what your function does, what is its purpose
* @params[in] - what are the inputs to your function, describe the inputs a little bit * @params[out] - what are the outputs of your function (if your function doesn't have any, then you can mention that there are no outputs and if you are making any internal changes then you can briefly describe them here)
*/

MODULARITY:

This is so important since it makes your code much readable and also helps with debugging since you can narrow the root of the cause much more easily. You should group your code into chunks of code that perform similar things or have a common goal. So in terms of cache lab, you could have a load function, a store function, an eviction function, a writeToCache function, etc. How many functions you have is really up to you (don't have too many otherwise that defeats the purpose) but don't put everything in the main. Functionality should not be repeated unless absolutely necessary (ie repeating code that could be extracted to a helper function), and functions should not become bloated. The definition of bloated may vary from function to function, for example your main function may necessarily become very long, while helper functions should remain somewhat concise.

CLEANING UP MEMORY:

Whatever you allocate (malloc, calloc, realloc) should be freed by the end of the program!

GIT:

Git is a version control system. We strongly suggest that you use git, for the reasons listed below. A portion of your style grade will be dependent on your usage of version control.

  • It helps you keep track of your progress, revert to an older working version of your code when your current code does not function correctly, switch between different versions of your code when you are trying out different designs and implementations;
  • It helps us correctly identify cases of academic integrity violation and helps you defend yourself from a potential false accusation of such: violation;
  • It helps you learn a tool that is used in industries and real-life production.

Here are a few good tips for using git. More can be found here.

  • Commit early and often.
  • Each commit should be one and only one logical change. For example, a bug fix and an optimization should be two separate commits. A bug fix that requires changes in two files should not be split into two separate commits.
  • Use the editor to write a commit message (git commit), don't supply a message via the -m option. To configure the editor git runs for commit messages, run git config --global core.editor your-editor.
  • Commit message should be a title of no more than 50 characters, followed by a blank line, then by a more thorough description.
  • Do not rewrite commit history. It is an important record of what actually happened to your code.

Finally, despite there being all the git tutorials and explanations out there in the internet, it is always a difficult task and a grave responsibility to pick one good resource and to recommend it to a class of over 200 people. One TA's personal recommendation is the book Pro Git that is available for free on the quasi-official website of git.