diff --git a/slides/12_clean_code.html b/slides/12_clean_code.html new file mode 100644 index 0000000..890e81b --- /dev/null +++ b/slides/12_clean_code.html @@ -0,0 +1,804 @@ + + + + + + + clean code + + + + + + + + + + +
+
+ +
+

clean code

+

Gergő Pintér, PhD

+

gergo.pinter@uni-corvinus.hu

+
+ +
+

manifesto for software craftsmanship

+
+
+

As aspiring Software Craftsmen we are raising the bar of professional +software development by practicing it and helping others learn the +craft. Through this work we have come to value:

+
    +
  • Not only working software, but also well-crafted +software
  • +
  • Not only responding to change, but also steadily adding +value
  • +
  • Not only individuals and interactions, but also a community +of professionals
  • +
  • Not only customer collaboration, but also productive +partnerships
  • +
+

That is, in pursuit of the items on the left we have found the items +on the right to be indispensable.

+
+
+ + +
+ +
+

software design and architecture stack

+
+based on Khalil Stemmel’s figure [1] + +
+
+ +
+

hierarchy in style guides

+
+
+ +
+

not just style guides, also best practices

+
+
+

+
+
+
+ +
+
+

write idiomatic code

+
+
+
+
    +
  • a prog. language implements a prog. paradigm
  • +
  • a paradigm defines a certain “way” of writing code +
      +
    • using different abstractions / building blocks
    • +
    • promoting a given concept
    • +
  • +
+
+
+
    +
  • some languages implements multiple paradigms
  • +
+
+
+
    +
  • and languages have their own way of doing things +
      +
    • languages have pros and cons
    • +
    • for a given problem
    • +
  • +
+
+
+

+
+
+
+

just as in the case of natural languages, you ought to use a language +properly

+
+
+
+

write idiomatic code

+
+
+
for (i = 0; i < 10; i++) {
+    console.log(i);
+}
+
+
[...Array(10).keys()].forEach(i => {
+    console.log(i);
+});
+
+
+
i = 0
+while i < 10:
+    print(i)
+    i += 1
+
+
for i in range(10):
+    print(i)
+
+
+
+
for i in 0..9 do
+   puts i
+end
+
+
+
(0..9).each do |i|
+    puts i
+end
+
+
+
(0..9).each {|i| puts i}
+
+
+
+
+
+

clean code

+

Clean Code: A Handbook of Agile Software Craftsmanship

+

by Robert C. Martin (2009) martin2009clean?

+
+

some recommendations are too specific to C-like languages

+
+
+ +
+
+

meaningful names

+
+
+

this section is based on the book Clean Code (chapter 2) by +Robert C. Martin martin2009clean?

+
+

+
+
+
+
+

use intention-revealing names

+
+
int d; // elapsed time in days
+
+

the definition is only available ad the declaration

+
+
int elapsedTimeInDays;
+
+

the definition is available at every usage

+
+
+
+
+

multi-word names

+
+
+

camelCase

+
+
int elapsedTimeInDays;
+
+
+
    +
  • C (local variable)
  • +
  • Java (variable, method)
  • +
+
+
+

UpperCamelCase (PascalCase)

+
public class DataCollector {}
+
+
    +
  • Java (class)
  • +
  • Rust (Type, Enum)
  • +
+
+
+

snake_case

+
+
elapsed_time_in_days = 17
+
+
+
    +
  • Python
  • +
  • Rust (variable, function)
  • +
+
+
+
+
+ +

a study states, camelCase is faster to type but snake_case is faster +to read sharif2010eye?

+
+
+

read the style guide

+
+
+
+

avoid disinformation

+
+

Do not refer to a grouping of accounts as an accountList +unless it’s actually a List martin2009clean?.

+
+
+

better to use accounts, it does not depend on the +collection name

+
+
+

inconsistent spellings is also disinformation

+
+
+
+

disinformative names would be the use of lower-case L or +uppercase O martin2009clean?

+
+
    +
  • they can look almost like the one and zero, respectively – use the +right font
  • +
  • PEP8 (Python style guide) forbids to use them
  • +
+
+
+
+

make meaningful distinctions

+
+

It is not sufficient to add number series or noise words, even though +the compiler is satisfied. If names must be different, then they should +also mean something different martin2009clean?.

+
+
+
def calculate_distance(data: pd.DataFrame) -> pd.Series:
+    # do something
+
def calculate_distance2(data: pd.DataFrame) -> pd.Series:
+    # do something else
+
+
def calculate_eucledian_distance(data: pd.DataFrame) -> pd.Series:
+    # ...
+
def calculate_levenshtein_distance(data: pd.DataFrame) -> pd.Series:
+    # ...
+
+
+
+
+

make meaningful distinctions / noise words

+
+

Noise words are another meaningless distinction. Imagine that you +have a Product class. If you have another called +ProductInfo or ProductData, you have made the +names different without making them mean anything different martin2009clean?.

+
+
+
+

use pronounceable names

+
+

If you can’t pronounce it, you can’t discuss it without sounding like +an idiot martin2009clean?.

+
+
    +
  • Should etid be an integer?
  • +
  • Should elapsed_time_in_days be an integer?
  • +
+
+

could be especially important for non-native speakers as some words +are more difficult to pronounce

+
+
+
+

use searchable names

+
+
+
+
+

Single-letter names can ONLY be used as local variables inside short +methods. The length of a name should correspond to the size of its scope +martin2009clean?.

+
+
+
+
+

it’s OK to do this:

+
for i in range(10):
+    print(i)
+
+

it’s NOT OK in a large scope:

+
int d; // elapsed time in days
+
+
+
+

+
+
+
+
+

names for classes, functions

+
+
+
    +
  • a class is a model / blueprint of something
  • +
  • the name should be a noun +
      +
    • e.g., User, Activity
    • +
  • +
  • an object is an instance of a class +
      +
    • still a noun
    • +
    • e.g., user = User()
    • +
  • +
+
+
    +
  • a function does something
  • +
  • the name should contain a verb +
      +
    • in imperative
    • +
    • e.g., aggregate_activity
    • +
    • activity_aggregation
    • +
  • +
+
+
+
+
+

avoid encodings

+

with modern IDEs it is pointless to put type or role markers into +names

+
+

Hungarian notation

+
    +
  • invented by Charles Simonyi at Microsoft
  • +
  • adding a prefix to a name that gives information about type, length, +or scope
  • +
+
def fnFactorial(iNum):
+    if iNum == 1:
+        return iNum
+    else:
+        return iNum * fnFactorial(iNum - 1)
+
+

source: bhargav2024hungarian?

+
+
+
+
+
interface IShapeArea // I is also a prefix
+{
+  void area(); 
+}
+
+
interface ShapeArea 
+{
+  void area(); 
+}
+
+
+
+
+

avoid mental mapping

+
+

Readers shouldn’t have to mentally translate your names into other +names they already know martin2009clean?.

+
+ +
+
+

+
+

+
+
+
+
+

don’t pun or use humor

+
    +
  • no inside jokes
  • +
  • no colloquialisms or slang
  • +
  • be objective and professional
  • +
+
+

Say what you mean. Mean what you say martin2009clean?.

+
+
+
+

pick one word per concept

+
+

it’s confusing to have fetch , retrieve, +and get as equivalent methods of different classes martin2009clean?

+
+

it also helps to search for the term

+
+
+

add meaningful context

+
+

Imagine that you have variables named firstName, lastName, street, +houseNumber, city, state, and zipcode. Taken together it’s pretty clear +that they form an address. But what if you just saw the state variable +being used alone in a method? martin2009clean?

+
+
    +
  • adding a prefix? +
      +
    • e.g., addrCity, addrStreet, +addrState
    • +
  • +
  • as notations are discouraged, use an Address class +instead to add context
  • +
+
+
+

functions

+
+
+

this section is based on the book Clean Code (chapter 3) by +Robert C. Martin martin2009clean?

+
+

+
+
+
+
+
[1]
K. +Stemmler, “How to learn software design and architecture.” + + https://khalilstemmler.com/articles/software-design-architecture/full-stack-software-design +, 28-Sep-2019.
+
+
+
+
+
+ + + + + + + + + + +