Sat, Jan 30, 2021
Read in 7 minutes
One common saying is that "good code should read like a story". And just like a story, code can have different type of code structures for readers to make sense of what the code is doing.
Some basic understanding of primitives and control flow. Familiar with if-else, while, for, etc.
https://hackr.io/blog/programming-paradigms - Good introduction. Can skip the section on logical programming, not very common in modern languages.
https://repl.it/ - Programming sandbox environment. Pick from any language and start playing with language features.
Head First Object-Oriented Analysis and Design: A Brain Friendly Guide to OOA&D by Brett McLaughin - Very fun and approachable book on understanding object oriented programming. Not matter how old, it is still relevant.
Software development and programming is mostly an exercise in thinking and expressing our thoughts into code. One common saying is that “good code should read like a story”. And just like a story, code can have different type of code structure for readers to make sense of what the code is doing. This is especially important for code that is co-developed by a team, where team members need to quickly understand what is going on in order to make changes.
Most programming languages support a mix of programming paradigms.
In the following we will attempt to get the same result using different programming paradigms.
As the name suggests, it is written in a way how you want the computer to carry out the procedure. It is code that literally hand-holds the computer through what you want it to do. It is also known as imperative programming.
list = ['apple', 'pear', 'orange']
index = 0
while index < list.length do
if list[index] == 'apple'
put 'found'
end
end
You can’t really escape procedural programming. After all, a computer is supposed to receive a set of instructions to do anything useful. However, the bulk of your thought process should not be thinking in procedures.
Functional programming has its roots from mathematics and relies heavily on using specific expressions to return values.
list = ['apple', 'pear', 'orange']
# This defines a function that calls itself
def find_apple(array)
if array.empty?
false
elsif array[0] == 'apple'
puts 'found'
else
find_apple(list[1..array.length])
end
end
# call the function
find_apple(list)
# this is another way, using 'reduce'
list.reduce(false) { |item|
if item == 'apple'
puts 'found'
else
false
end
}
map
, reduce
).Simple functional programming principles can help you express your intent clearer and reduce surprises in your code. For example, when writing functions, separate the pure effects from impure effects. Example:
# --------------
# Impure example
def upcase_and_print(string)
string.upcase! # the ! changes the original
puts string # < writing to terminal is a side-effect
end
text = "hello"
upcase_and_print(text) # ==> "HELLO"
puts text # ==> "HELLO" -> this changed text by surprise
# ------------------------
# Separate pure and impure
def upcase(string)
return string.upcase # this doens't change the original
end
def print(string)
puts string
end
text = "hello"
new_text = upcase(text)
print(new_text) # ==> "HELLO"
puts text # ==> "hello" --> this doesn't change original by surprise
As the name suggests, object oriented programming (OOP) is built around modelling things in the real world. Modelling software against real world objects is a natural (and correct) thing to do, and most people are able to pick up the basics quickly. It is also a fact that the invention of OOP paved the way for large and complex software to be built for the modern world.
class Fruit
attr_reader :name # this line makes name publicly accessible
def initialize(name)
# the '@' makes the variable specific to only this instance
# You can have many instances of Fruit, and this allows each to have
# different names that they maintain internally
@name = name
end
end
class Basket
def initialize(items)
@items = items
end
def find_item(name) # this is known as a 'method'
if @items.find { |item| item.name == name }
puts 'found'
end
end
end
list = [Fruit.new('apple'), Fruit.new('pear'), Fruit.new('orange')]
basket = Basket.new(list)
basket.find_fruit('apple') # ==> 'found'
interface
, Ruby calls it module
, Swift calls it protocol
, Python calls it mixin
, C++ calls it abstract class
. They kinda mean the same thing of sharing functions between classes, but also different in a significant way that affects your code structure).OOP should be the first thing that all new engineers learn. It is a common skill among engineers and most projects use OOP, so it is easy to slip into a project if needed. It also helps to promote critical thinking around where’s the best places to keep data and separate responsibility between classes.
There is more than 1 way to get the same result. What you choose depends on who and what you are working with. There are even more paradigms that are not discussed here like declarative (SQL), logical (Prolog) and more. Feel free to go down the rabbit hole at your own time.
I highly recommend trying out writing a couple of lines of code in OOP to get a feel of how it works. A basic exercise:
Create a class called Money
that holds information about amount
and currency
.
Create a class called LineItem
that holds information about transaction name
and spending
.
Spending should be an instance of Money
.
Line item should have a method called print
that outputs the value in a specific format.
spending = Money.new(100.00, 'SGD')
line_item = LineItem.new('clothes', spending)
line_item.print # You should see 'clothes SGD 100.00'
Fire up your web browser and search for object oriented programming for some programming languages you have heard of (e.g. search object oriented programming python
)
Look for similarities and differences in the way how each language
Popular languages are more similar than different. This exercise helps you to gain confidence that programming structure is more important than language specific syntax.
Learning to write software? Subscribe now to receive tips on software engineering.