Rules You Can Break, And Rules You Can't
An example that bugged me always was: “do class names need to start with uppercase?”
Follow the Rules
When I started learning to program, I felt that all the rules were mandatory. I always had to do it the way I learned. With time, I began to differentiate which rules I can break and which not. This allowed me to learn new languages and tools faster. As well as write more readable and maintainable code.
An example of this that bugged me was: “do class names need to start with uppercase?”
In development, we use many different systems and components: servers, libraries, programming languages, runtime environments, browsers, networks, etc. Different components have different ways in which they work and different rules. With so many moving parts, it’s difficult to tell when we can break a rule or not.
To know when we can break a rule, we need to understand a few key concepts and their differences: protocols, syntax, semantics, conventions, defaults, and best practices.
Rules We Cannot Break: Protocols
Protocols are a list of rules that define how a set of components interact. If one doesn’t follow the rules, their interaction doesn’t work correctly.
An example is the Hypertext Transfer Protocol (or HTTP), which powers most of the Internet. HTTP defines a set of rules of how computers talk to each other. These rules are ingrained in our tools, and most of the time, we don’t even realize that we are using this protocol. Only people that develop low-level tools care about the specifics.
Another example is Cookies, even though HTTP-Cookies are not considered a protocol, it defines how two components, server, and browser, interact to share and maintain information across requests.
Protocols are rules that we cannot break.
Rules We Cannot Break: Syntax
The syntax of a language is the set of rules on how to write code. So when we get a “Syntax Error,” it’s because we haven’t followed the rules of the language.
For example, if you try the following in the console: const a = () { return 0 };
, you will get a syntax error. This error occurs because the syntax of the statement is incorrect.
// NOT VALID
const a = () { return 0 };
// VALID
const a = () => { return 0 };
// VALID
const a = function () { return 0 };
Syntax rules cannot be broken.
Rules We Cannot Break: Semantics
Programming languages are more than their syntax. For example, type checking in typed languages is a semantic rule. The syntax might be correct, but if the types don’t match, the program doesn’t compile.
You can try the following in the browser’s console to get a semantic error:
> const b = 10;
undefined
> b = 20
VM479:1 Uncaught TypeError: Assignment to constant variable.
at <anonymous>:1:3
In Javascript, we cannot reassign a variable declared with the const
keyword, the syntax of both statements is correct, but not the semantics.
A great example of syntax versus semantics in English is the following sentence by Noam Chomsky: "Colorless green ideas sleep furiously." The phrase is syntactically correct, but the meaning is gibberish.
To help understand semantics and syntax, I recommend my previous article on EBNF, a meta-programming language to write syntax of languages.
Semantics are rules we cannot break.
Rules We Can Break: Conventions
There are two types of conventions:
Conventions over configuration
Socially shared conventions
Conventions Over Configuration
This is a software design paradigm that aims to decrease the number of decisions that the developer using the framework has to make. The most popular framework example with convention over configuration is Ruby On Rails.
When the conventions match the behavior desired by the developer, no configuration files are needed. Configuration files are only required when the desired behavior deviates from the default.
Socially Shared Conventions
Shared conventions are a set of rules that a group has agreed upon, usually a community around a framework or a programming language. A famous example is the snake case naming for Python.
These socially accepted conventions are not technical limitations. Instead, they increase the readability and maintainability of systems by adding consistency in the tool’s usage.
Conventions are rules we can break.
Rules We Can Break: Defaults
A default is a preexisting value in a software application, module, or computer program. For example, it might be a default in a tool from a third party or internal from the company. Defaults are usually easily overridden.
A simple example is the “.join” method on arrays in Javascript:
> [1,2,3].join();
'1,2,3'
> [1,2,3].join(' ');
'1 2 3'
The default behavior is to put together the elements separated by a comma. Yet, we can change the method's behavior by passing a string when calling `.join()`.
I’d like to point out a few defaults that are so common that they look like rules:
Using
master
ormain
as the principal branch in git.Using
www
when visiting a website. Check out this Quora answer for more details.Web Servers and
index.html
.
Defaults are rules we can break.
Rules We Can Break: Best Practices
Best practices are guidelines or design principles to make software projects more understandable, flexible, and maintainable. A popular example is the SOLID principles.
The SOLID principles are generic to software development, but other best practices are specific to tools or programming languages. For example, a standard best practice when using the Redux library is to use immutability for the whole state.
Best Practices are rules we can break.
There Are Rules and "Rules"
We have learned six different categories of rules: protocols, syntax, semantics, conventions, defaults, and best practices. The difference is sometimes blurry, especially among the last three. Yet, the next time you encounter a rule, I encourage you to put it in one of these buckets.
Now we can ask ourselves: “Which rule makes classes start with an uppercase letter?”
We have also seen that some rules can be broken and others not. This differentiation is key to learning new tools and keeping up to date. Best practices evolve, defaults change, and conventions come and go. Syntax and semantics might change in recent versions of programming languages, new protocols can appear, and old ones can change. Understanding the differences in rules puts us in a better position for the future.
I’d like to end with a recommendation: “Focus on learning best the rules that have been longer because they will probably stay longer.” This is known as the Lindy Effect: the life expectancy of something is proportional to its current age.
If you like this post, consider sharing it with your friends on twitter or forwarding this email to them 🙈
Don't hesitate to reach out to me if you have any questions or see an error. I highly appreciate it.
And thanks to Michal for reviewing this article 🙏