Functions
Key Takeaways
- Functions should do one thing and do it well.
- They should be short.
- Have well described names so it is clear what they do (a verb)
- Arguments should be nouns
- Functions shouldn't really have more than 2 arguments:
- Niladic: takes no arguments is ideal
- Monadic: takes one argument, should only be used if altering the argument and returning it or returning information about the argument.
- Dyadic: takes two arguments, should usually be avoided. A good use case as an example is a 2D coordinate function.
- Triads: takes three arguments, hard to understand and test for (due to the different combinations). Should be avoided and usually can be.
- Often multiple arguments are related and can be combined into an object. For example rather than passing in an x and y coordinate, why not pass them in as a Point object.
- Flag arguments are problematic, passing a boolean into a function instantly flags that the function is doing more than one thing. If true do this, else do this.
- A function shouldn't have side effects, a side effect means that the function is doing something else that isn't told or obvious in order to do its task.
- Example in book is initializing a session to validate a password. Initializing the session isn't really told explicitly so you could be unaware that you're starting a new session when you want to validate a password. This could lead to you losing your current session data.
- Indent level of a function shouldn't be greater than 1 or 2.
- A function should either do something or answer something, not both.
- We prefer exceptions over error codes.
- Remember that we want a function to do one thing, and Error Handling is one thing and hence needs its own functions, etc.
- One level of abstraction per function.
- We want to extract try and catch blocks and use same principles when error handling. See example below and how it can be improved:
try {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
catch (Exception e) {
logger.log(e.getMessage())
}
Above is doing too much, let's make it better:
public void delete(Page page) {
try {
deletePageAndAllReferences(page);
}
catch (Exception e) {
logError(e);
}
}
private void deletePageAndAllReferences(Page page) throw Exception {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
private void logError(Exception e) {
logger.log(e.getMessage());
}