CRAFTING CLEAN CODE Ganesh Samarthyam
“Keeping “clean” is a habit - it’s not to do with “skills” or “ability”!
WARM-UP EXERCISE
ASSUME MANY PLACES YOU HAVE SUCH CODE- HOW TO IMPROVE? #include <vector> #include <iostream> using namespace std; bool validate_temperature_measures(vector<int> &measures) { for(vector<int>::iterator i = measures.begin(); i != measures.end(); ++i ) { if( *i < 0 || *i > 100) { return false; } } return true; } int main() { vector<int> measures = { 23, 66, 25, 85, 110, 45, 34, 90 }; cout << "valid measures? " << std::boolalpha << validate_temperature_measures(measures) << endl; }
ATTEMPT #1 #include <vector> #include <algorithm> #include <iostream> using namespace std; template<typename T> class is_outside_range : public unary_function<T, bool> { public: is_outside_range(const T& low, const T& high) : low_(low), high_(high) {} bool operator()( const T& val ) const {return val < low_ || val > high_; } private: T low_, high_; }; bool validate_temperature_measures(vector<int> &measures) { vector<int>::iterator result = find_if(measures.begin(), measures.end(), is_outside_range<int>(0, 100)); return result == measures.end(); } int main() { vector<int> measures = { 23, 66, 25, 85, 10, 45, 34, 90 }; cout << "valid measures? " << std::boolalpha << validate_temperature_measures(measures) << endl; }
ATTEMPT #2 #include <vector> #include <algorithm> #include <functional> #include <iostream> using namespace std; bool validate_temperature_measures(vector<int> &measures) { function<bool(int)> temperature_validator = [](const int value) { const int low = 0; const int high = 100; return (value < low) || (value > high); }; vector<int>::iterator result = find_if(measures.begin(), measures.end(), temperature_validator); return result == measures.end(); } int main() { vector<int> measures = { 23, 66, 25, 85, 10, 45, 34, 90 }; cout << "valid measures? " << std::boolalpha << validate_temperature_measures(measures) << endl; }
GETTING STARTED
ESSENTIALS ➤ Ensure traceability within code ➤ Do not write “sloppy code” ➤ Provide necessary copyright notice, change logs, etc. in each source and header files
FORMATTING ➤ “Consistency” is key to formatting ➤ Example: placement of curly braces - “{“ and “}” ➤ Another obvious example: tabs vs. whitespaces ➤ Keep lines within 80 characters ➤ Ensure “density” is not too high ➤ E.g., leave out enough a linespace between group of statements ➤ Have an ordering of member functions, data members, etc. ➤ Ensure proper intendation
MEANINGFUL NAMES ➤ Use intention-revealing names int d; // elapsed time in days int elapsedTimeInDays; ➤ Use searchable names for(int j = 0; j < 34; j++) s+= (t(j)*4)/5; int realDaysPerIdealDay = 4; const int WORK_DAYS_PER_WEEK = 5; int sum = 0; for(int task; task < NUMBER_OF_TASKS; j++) { int realTaskDays = taskEstimate[task] * realDaysPerIdealDay; int realTaskWeeks = (realDays / WORK_DAYS_PER_WEEK); sum += realTaskWeeks; } Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, Prentice Hall, 2008
NAMING ➤ Avoid Hungarian notation and member prefixes ➤ Class names should have noun or noun phrases (and not be a verb) ➤ Method names should have verb or verb phrase names ➤ Avoid typos and smelling mistakes in the code
COMMENTS ➤ Provide good “internal documentation” ➤ Comments do not make up for bad code ➤ Explain yourself in code ➤ Explain intent ➤ Avoid commenting-out code ➤ Avoid redundant comments ➤ Provide mandated comments ➤ Use position markers sparingly (e.g., // Actions ////////) Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, Prentice Hall, 2008
FUNCTIONS / METHODS ➤ Avoid macros - use inline functions instead ➤ Method names - neither too long, nor too short ➤ Keep parameter list small (not more than 4 or so parameters) ➤ Avoid “out” parameters - prefer return values instead ➤ Avoid friend functions ➤ Prefer const methods ➤ Ensure proper return from all paths ➤ Strive for exception safety
FUNCTIONS / METHODS ➤ Keep nesting level of functions low (not more than 3 or 4 levels deep) ➤ Keep Cyclomatic complexity low (less than 10 per method) ➤ Keep lines size small (more than 10 or so becomes difficult to grasp) ➤ Avoid functions doing many things - do one thing (e.g., realloc does too many things) ➤ Avoid “stateful-functions” (e.g., strtok)
CLASSES ➤ Prefer one class per file ➤ Limit the number of members in a class ➤ Avoid public data members ➤ Limit the accessibility of the class members ➤ Have a ordering for the methods and data members; order public, private, and protected members ➤ Keep the complexity of classes low - i.e., Weighted Methods per Class (WMC) keep it low like 25 or 30 ➤ Avoid “struct-like” classes
HARDCODING ➤ Avoid “hard-coded logic” ➤ Avoid “magic numbers” ➤ Avoid “magic strings”
“Adopt a coding standard and adhere to it (as a team!)
“Code without unit tests is legacy code!
CODING GUIDELINES
MISRA C/C++ https://www.misra-cpp.com/MISRACHome/tabid/128/Default.aspx
CERT C++ https://www.cert.org/downloads/secure-coding/assets/sei-cert-cpp-coding-standard-2016-v01.pdf
JSF++ http://www.stroustrup.com/JSF-AV-rules.pdf Designed by Lockheed Martin for Joint Strike Fighter - Air Vehicle coding standard for C++
HIGH-INTEGRITY C++ CODING STANDARD http://www.codingstandard.com/section/index/
GOOGLE C++ STYLE GUIDE https://google.github.io/styleguide/cppguide.html
C++ CORE GUIDELINES http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
ganesh@codeops.tech @GSamarthyam www.codeops.tech slideshare.net/sgganesh +91 98801 64463 bit.ly/sgganesh

Coding Guidelines - Crafting Clean Code

  • 1.
  • 3.
    “Keeping “clean” isa habit - it’s not to do with “skills” or “ability”!
  • 4.
  • 5.
    ASSUME MANY PLACESYOU HAVE SUCH CODE- HOW TO IMPROVE? #include <vector> #include <iostream> using namespace std; bool validate_temperature_measures(vector<int> &measures) { for(vector<int>::iterator i = measures.begin(); i != measures.end(); ++i ) { if( *i < 0 || *i > 100) { return false; } } return true; } int main() { vector<int> measures = { 23, 66, 25, 85, 110, 45, 34, 90 }; cout << "valid measures? " << std::boolalpha << validate_temperature_measures(measures) << endl; }
  • 6.
    ATTEMPT #1 #include <vector> #include<algorithm> #include <iostream> using namespace std; template<typename T> class is_outside_range : public unary_function<T, bool> { public: is_outside_range(const T& low, const T& high) : low_(low), high_(high) {} bool operator()( const T& val ) const {return val < low_ || val > high_; } private: T low_, high_; }; bool validate_temperature_measures(vector<int> &measures) { vector<int>::iterator result = find_if(measures.begin(), measures.end(), is_outside_range<int>(0, 100)); return result == measures.end(); } int main() { vector<int> measures = { 23, 66, 25, 85, 10, 45, 34, 90 }; cout << "valid measures? " << std::boolalpha << validate_temperature_measures(measures) << endl; }
  • 7.
    ATTEMPT #2 #include <vector> #include<algorithm> #include <functional> #include <iostream> using namespace std; bool validate_temperature_measures(vector<int> &measures) { function<bool(int)> temperature_validator = [](const int value) { const int low = 0; const int high = 100; return (value < low) || (value > high); }; vector<int>::iterator result = find_if(measures.begin(), measures.end(), temperature_validator); return result == measures.end(); } int main() { vector<int> measures = { 23, 66, 25, 85, 10, 45, 34, 90 }; cout << "valid measures? " << std::boolalpha << validate_temperature_measures(measures) << endl; }
  • 8.
  • 9.
    ESSENTIALS ➤ Ensure traceabilitywithin code ➤ Do not write “sloppy code” ➤ Provide necessary copyright notice, change logs, etc. in each source and header files
  • 10.
    FORMATTING ➤ “Consistency” iskey to formatting ➤ Example: placement of curly braces - “{“ and “}” ➤ Another obvious example: tabs vs. whitespaces ➤ Keep lines within 80 characters ➤ Ensure “density” is not too high ➤ E.g., leave out enough a linespace between group of statements ➤ Have an ordering of member functions, data members, etc. ➤ Ensure proper intendation
  • 11.
    MEANINGFUL NAMES ➤ Useintention-revealing names int d; // elapsed time in days int elapsedTimeInDays; ➤ Use searchable names for(int j = 0; j < 34; j++) s+= (t(j)*4)/5; int realDaysPerIdealDay = 4; const int WORK_DAYS_PER_WEEK = 5; int sum = 0; for(int task; task < NUMBER_OF_TASKS; j++) { int realTaskDays = taskEstimate[task] * realDaysPerIdealDay; int realTaskWeeks = (realDays / WORK_DAYS_PER_WEEK); sum += realTaskWeeks; } Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, Prentice Hall, 2008
  • 12.
    NAMING ➤ Avoid Hungariannotation and member prefixes ➤ Class names should have noun or noun phrases (and not be a verb) ➤ Method names should have verb or verb phrase names ➤ Avoid typos and smelling mistakes in the code
  • 13.
    COMMENTS ➤ Provide good“internal documentation” ➤ Comments do not make up for bad code ➤ Explain yourself in code ➤ Explain intent ➤ Avoid commenting-out code ➤ Avoid redundant comments ➤ Provide mandated comments ➤ Use position markers sparingly (e.g., // Actions ////////) Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, Prentice Hall, 2008
  • 14.
    FUNCTIONS / METHODS ➤Avoid macros - use inline functions instead ➤ Method names - neither too long, nor too short ➤ Keep parameter list small (not more than 4 or so parameters) ➤ Avoid “out” parameters - prefer return values instead ➤ Avoid friend functions ➤ Prefer const methods ➤ Ensure proper return from all paths ➤ Strive for exception safety
  • 15.
    FUNCTIONS / METHODS ➤Keep nesting level of functions low (not more than 3 or 4 levels deep) ➤ Keep Cyclomatic complexity low (less than 10 per method) ➤ Keep lines size small (more than 10 or so becomes difficult to grasp) ➤ Avoid functions doing many things - do one thing (e.g., realloc does too many things) ➤ Avoid “stateful-functions” (e.g., strtok)
  • 16.
    CLASSES ➤ Prefer oneclass per file ➤ Limit the number of members in a class ➤ Avoid public data members ➤ Limit the accessibility of the class members ➤ Have a ordering for the methods and data members; order public, private, and protected members ➤ Keep the complexity of classes low - i.e., Weighted Methods per Class (WMC) keep it low like 25 or 30 ➤ Avoid “struct-like” classes
  • 17.
    HARDCODING ➤ Avoid “hard-codedlogic” ➤ Avoid “magic numbers” ➤ Avoid “magic strings”
  • 18.
    “Adopt a codingstandard and adhere to it (as a team!)
  • 19.
    “Code without unittests is legacy code!
  • 20.
  • 21.
  • 22.
  • 23.
    JSF++ http://www.stroustrup.com/JSF-AV-rules.pdf Designed by LockheedMartin for Joint Strike Fighter - Air Vehicle coding standard for C++
  • 24.
    HIGH-INTEGRITY C++ CODINGSTANDARD http://www.codingstandard.com/section/index/
  • 25.
    GOOGLE C++ STYLEGUIDE https://google.github.io/styleguide/cppguide.html
  • 26.
  • 27.