Engineering 101: Understanding bits and bytes

Kevin NaidooKevin Naidoo
27 min read

In my early years, when my age was still single digits, I was tearing apart electrical things like there’s no tomorrow. I was trying to understand how they tick. How do they work? Where do sounds and pictures come from on TV? What happens when this VCR thing (the device that played movies before CDs and DVDs) reads the tape?

Not fun for my parents, as you can imagine 🙈

Nonetheless, this inquisitiveness has helped me a ton throughout my career. I love building stuff, but I love tearing things apart even more! I am never content with “It just works.” I always ask why.

As a software engineer, this is a vital skill to have, especially now in the modern era of AI, where code is just being generated willy-nilly. Understanding computer fundamentals will help you immensely in the long run to sustain a long and fruitful career in tech.

The goal of this article is to make you stop and think for a second about your code and what is actually happening when you hit that “build,” or “compile,” or “run” button.

ℹ️ I will use a mixture of languages to demostrate some concepts (Usually Python and Golang), you do not need to understand these languages just yet, since the goal is to teach you how to think like an Engineer, such that you can apply this knowledge to just about any language.

Programming is just 1s and 0s, essentially electrical signals

Computer hardware can only understand one language: either turn on the flow of electricity in a pathway or turn it off.

Thus, regardless of the programming language you use, everything gets compiled down to machine code. Which is a set of instructions your operating system eventually passes down to the hardware in your computer as electrical signals.

Now, obviously, you cannot send raw 1s and 0s to the hardware; this is why we have operating systems and something known as machine code.

Operating systems are responsible for actually taking the machine code and converting it into electrical signals. Not all devices have an operating system, some just have smaller programs, often referred to as embedded systems, nonetheless, they perform a similar role to that of a big OS like Windows, Linux, or Mac OS.

Machine code is the lowest level of software abstraction and the last mile before code becomes electricity inside transistors. Essentially, machine code is a chain of ones and zeros, arranged together in a particular sequence.

Think of a computer monitor. It’s made up of millions of pixels of colors, i.e., dots. When we need to print the words “Hello World” to the screen, we send the OS machine code that may look like this “1111 1101 1011 1111 1101 1111 1011” (Of course, I just made up this sequence for demonstration purposes).

Using this sequence, the system determines which pixels need to light up to form the shapes of "H-e-l-l-o W-o-r-l-d" according to the selected font, size, and color.

When you write a program, your code looks similar to written languages like English, albeit with a bit of math and symbols, but essentially it’s human-readable. This is by design, because we humans cannot manage thousands of 1s and 0s; it’ll be almost impossible to read and write accurately.

This is why we invented programming languages; they offer a high level of abstraction, allowing programmers to write code in a readable language, but also write code in a structured way so that it can be later converted into electrical signals.

Translator programs

Since programming languages aren’t written in machine code, the Operating System itself cannot understand your code. Instead, we need a translator program, something that can read your code and convert it to machine code.

Whenever you start working with a new programming language, you’ll often need to download and install some kind of runtime program like the Python interpreter or Node, or the JVM, and so forth.

While most of these runtimes come with various libraries and tools, at the heart of each runtime is a translator program of some sort.

There are many variations of translator programs, but generally, these are the most common:

  • Compilers. In Golang, for example, the compiler runs once and generates what is known as an “executable”. This is your entire program in a binary format. To distribute your program, you no longer need the source code (the code you type in your coding editor) or the runtime to run the executable program, since it’s now machine code and can be executed directly by the Operating System.

  • Interpreters. In the case of languages like Python, you do not build a single executable. Instead, you need to distribute your source code files, and in order for the target machine to run it, it needs to have the Python interpreter installed. While the interpreter may convert the program to an intermediary format like “bytecode” (we’ll talk about this soon), it’s not machine code and still needs processing to become machine code. So basically, interpreters read and convert your program’s code to machine code at runtime, hence why Python is much slower than Golang in terms of execution speed.

  • JIT compilers. A best of both worlds, Node.js is a good example. When you distribute your program, it’s distributed as source code. When the program is first run, the JIT compiler will analyze your code and convert frequently used portions into binary code similar to a compiler. It further monitors and optimizes the code as the program is running.

So, in summary, translator programs like the Golang compiler are responsible for taking code you write in your code editor and converting that to machine code, such that your operating system can then execute and eventually convert those to electrical signals.

💡 “Parsing” is a step in the tranlation process of your code into an executable program. The translator program reads your code and analyzers it against the syntax rules of the programming language being used. During this process the parser will also throw errors if any exist in your code. Which can crash your program or cause the compiler to not generate an executable binary, depending on the type of translator program.

So, what is “Byte Code”

In the past, interpreters were simple; they read your source code at runtime, line by line, and then converted it to binary code, which then got executed. This all happened in real-time. The problem with this approach is it’s slow, too slow for modern times where applications are doing much more work and have many more users running the program concurrently, especially on the web.

Modern interpreters like the Python Interpreter have a caching mechanism. Instead of constantly re-reading the source code and going through all the startup steps like parsing over and over again, the Python interpreter will transform your raw source code into “.pyc” files.

This is not machine code, it’s basically just an optimized version of your source that’s already gone through the initial startup steps, like parsing. It’s not yet readable by the operating system. Bytecode is designed to be readable by the Python interpreter. The interpreter still has to execute this bytecode at runtime, translating each bytecode into an instruction for the computer to execute.

When you “publish” your application code, that version of code won’t change until you publish an update, so the parsing (and other code processing stages) only needs to happen once and thereafter the interpreter knows that your code is valid and has passed all the checks thus it doesn’t need to keep redoing all these steps.

While interpreters are slower than compilers, they do offer the benefit of hot-swapping code. In a compiled program, you have to recompile the entire program whenever you make a change and then redeploy that binary.

With interpreters like the Python interpreter, you can simply change the file(s) that have been updated, and the interpreter will automatically recreate “.pyc” files only for what has changed. This makes it easier to debug code or deploy portions of your code while the program is still running (you may still need to restart the application for all parts of your program to see the update).

So in summary, a “translator” program (like compilers or interpreters) takes source code (structured human-readable instructions for the computer) that you type in a code editor like VScode and converts that to machine code. Machine code is binary instructions (1s and 0s) that the computer's processor can understand and execute.

What are Bytes?

Each bit (binary digit) does one very simple job: either on (1) or off (0), letting current through or not. Alone, this doesn’t amount to much, but together in a large program with millions of 1s and 0s arranged in a certain way, that program can achieve quite complex results like playing a movie or sending an email, and so on.

Now, imagine you own an electronics company, and your company sells TVs:

  • The customer buys a finished TV, not the list of internal components or the names of engineers who assembled it.

  • They don’t care which team achieved what or was responsible for which component.

  • What they see is the final product: the TV. They don’t even see the components inside the TV, they just see the TV as a whole.

💡 Abstraction is about hiding complexity and exposing only what’s necessary.

The purpose of the above example is to make you understand what “Abstraction” is, because from here on out, when we move away from simple 1s and 0s, we start to get into the software realm, where programmers use varying levels of abstractions to ultimately achieve some result.

At the highest level, you write a program in a language of your choice, let’s say Python. This program consists of instructions written in human-readable code. Example:

print("Hello world!")

Eventually, the translator program will convert this into machine code (just made up for illustration purposes):

10110000 01100001
10110001 01100010

When looking at the machine code closely, you’ll notice that each block of numbers is exactly 8 digits long. This is what a “Byte” is: it’s a grouping of binary numbers in sequences of eight. Each Byte is, therefore, a “box” of sorts; it stores digital information by arranging 1s and 0s in different patterns (maximum 8 bits).

In the case of print(“Hello world!”) . Each letter or symbol is represented by a byte, which could look like:

p   -> 112 -> 01110000
r   -> 114 -> 01110010
i   -> 105 -> 01101001
n   -> 110 -> 01101110
t   -> 116 -> 01110100
(   -> 40  -> 00101000
"   -> 34  -> 00100010
H   -> 72  -> 01001000
e   -> 101 -> 01100101
l   -> 108 -> 01101100
l   -> 108 -> 01101100
o   -> 111 -> 01101111
    -> 32  -> 00100000
w   -> 119 -> 01110111
o   -> 111 -> 01101111
r   -> 114 -> 01110010
l   -> 108 -> 01101100
d   -> 100 -> 01100100
!   -> 33  -> 00100001
"   -> 34  -> 00100010
)   -> 41  -> 00101001

As you can see by arranging the 1s and 0s in different sequences, we can represent letters, numbers, and symbols.

If you look closely, we also have numbers 112, 114, 105, and so on. This is another significant thing to understand about bytes. A byte can only store numbers, you cannot put “p” into a Byte because computers only understand numbers. Thus, we assign a number to each character (this is known as character encoding, more on that later).

When you arrange the 1s and 0s together in a group of eight, these patterns have a maximum of 256 different combinations. Thus, a Byte can hold a number from 0 to 255.

In the real world, we use “Grams” to weigh things. Often in the real world, Grams numerically become too large and cumbersome to work with. It’s far easier to write and read 10 kg versus 10,000 grams.

Similarly, in the computing world, most programs will easily exceed 1000 Bytes. So a number like 1,073,152 Bytes can become really cumbersome to comprehend as a human, instead we also have bigger units of measure like Kilobytes, Megabytes, Gigabytes, and so on.

These measures work as follows:

  • 1KB = 1024 Bytes

  • 1MB = 1024 Kilobytes

  • 1GB = 1024 MB

Note: Due to marketing and varying hardware manufacturers, some use units of thousands, i.e., 1000 KB, 1000 MB instead of 1024.

In summary, a “Byte” is a virtual unit of measure that is standardized across all computing systems. It groups together 8 bits (8 1s and 0s), and can be thought of as a “box” that can hold a number from 0 to 255.

What is character encoding?

On a mobile device, using icons and GIFs is common to convey certain meanings. We do this because, well, we’re chilling and lazy to type 🙃. Why type out a whole phrase, “I am so happy right now!” when you can just send a smiley face emoji?

Most people worldwide, regardless of what language they speak, can understand what an emoji means because at some point, we all agreed that 😃 means happy and ☹️means sad. For each of these emojis, we associated an emotion and globally accepted this meaning.

In computers, we know that there are just 2 digits that represent everything, either 1 or 0. When we group these two digits together, we can attach a more complex meaning to a Byte of data.

Still, a Byte can only represent numbers and the maximum number of 255. So, how on earth do we represent letters, let alone emojis?

To solve this problem, computer scientists developed character encodings. Character encodings basically associate a letter or character with a particular byte or bytes. Thus, character encodings are simply a standard of meaning for converting characters into bytes.

One of the earliest character encodings that worked well with the English language was known as “ASCII”. Similar to the emoji analogy, in ASCII, each character was associated with a particular number from 0 to 127, allowing the computer to capture the meaning of each character in a numerical format.

💡 This version of ASCII we’re talking about is know as “Standard ASCII”. later versions of ASCII can also use up more than 127.

Remembering our discussion on Bytes, you’ll recall that a Byte can store any number from 0 to 255. So, essentially, each ASCII encoding can be represented by a single Byte. Furthermore, each ASCII character only needs 7 bits out of the potential 8 bits in a byte (so at least one bit will always be off ‘0’).

💡 Notice how everything starts at 0. This is vital for later on in your career, because this pattern persists throughout programming. Especially in data structures like Arrays, in most languages these always start at zero.

While still used today in many systems, ASCII became very limited later when we needed to store more complex characters, such as emojis and characters from other languages, like Japanese. To solve this problem, a more robust encoding system, known as Unicode, was introduced.

Unicode is a tad bit more complex, like ASCII, it allows us to represent characters in a numerical form known as “code points”; however, Unicode itself is just a standard (Like a piece of paper with a list of rules to follow). You still need a system to actually store those code points inside Bytes.

These systems are known as encoding schemas, and there are a few varying implementations, like UTF-8, UTF-16, or UTF-32.

UTF-8 is the most popular, it basically uses up to 4 bytes to store characters. A simple English character would use 1 byte, however, some characters from a more complex language like Japanese can use 2-4 Bytes.

Encodings don’t only apply to text or characters; you also get encoding systems like the RGB system, which basically represents a colour using the 0-255 range. RGB uses 3 bytes to do this; each byte provides a value from 0 to 255 for the red, green, and blue color channels, respectively. By combining these three primary colors at different intensities, RGB encoding can represent approximately millions of different colours.

Some RGB examples:

rgb(255, 0, 0) ~ Red
rgb(0, 0, 255) ~ Blue
rgb(0, 255, 0) ~ Green
rgb(238, 130, 238) ~ Pink

The math of Binary

In regular math, we are accustomed to the base 10 system, 1-10-100. Since we have a maximum of 10 digits(0-9), every time we reach the number 9, we need to “reset,” which means we add a 0 to the right, and the number on the left increases by 1.

9
10
11
12
13
15
15
16
17
18
19
20
21

Now, when we get to 9, we have run out of numbers. We can’t add 1 to the left because “9” is the highest digit in the numbering system. When this happens, we simply replace each “9” with a “0” and then add 1 to the far left, i.e., 10; the same applies to 99, 999, and so on.

9 + 1 = 10       = 10¹
99 + 1 = 100     = 10²
999 + 1 = 1000   = 10³
9999 + 1 = 10000 = 10

Essentially, we are always working from right to left; we check the rightmost number to see if it’s 9, and if so, we apply the rules as per above. This is known as positional notation.

In base-10, when you reach a 9, you need to reset by adding a zero. In binary, it’s similar except you just add 1 or 0 to the left, so you effectively just increase the width of bits.

So to convert a binary number into a base 10 number, we use this width to determine how far this bit appears from the right (so effectively it’s position starting from 0, incrementing by 1 the further you go left).

Once you determine the position, this is now the power you must raise by a base of 2 to calculate the corresponding base-10 value.

In the case of 1 byte, the 8th number will be 2^0 (remember we always start with a zero), the 7th number 2^1, the 6th number 2². The further left you go, the higher the power. In the case of a Byte, the maximum power we can raise to is “7”, which is basically: 2×2×2×2×2×2×2=128

2^0 × 1 = 1
2^1 × 1 = 2
2^2 × 1 = 4
2^3 × 1 = 8
2^4 × 1 = 16
2^5 × 1 = 32
2^6 × 1 = 64
2^7 × 1 = 128
--------------------
Total     = 255

The above is a calculation based on a single Byte, where all values are “1” 11111111 This is the maximum value a Byte can hold, which, as you can see, adds up to 255.

What is a variable?

Since compilers and interpreters take care of converting code into bytes, we don’t often need to worry about how the code is translated and mapped on a character level. Instead, programming languages introduce their own “box” to put stuff in, called a “variable”.

A variable is essentially x number of Bytes that are grouped together to hold a certain portion of information, like a word or number, or even an image. I say “x” because, unlike a Byte, which has a fixed size of 8 bits, variables can be made up of any number of Bytes.

The number 52 For example can fit in a single Byte. Whereas an image would take up hundreds, if not thousands, of Bytes. Regardless of the size of either of these two entities, we can still store them in a single variable:

the_number_fifty_two = 52
profile_pic = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z"/></svg>'

In addition to a variable being able to store varied information, the box or size of the variable can also grow or shrink as you add or remove data. Example: when the variable is first created, we only have 2 names:

names = ["Kevin", "John"]

But, after we run the program, some process appends more names to the list, and thus our variable automatically grows in memory to accommodate more items:

.... do some computation to change names ....
names = ["Kevin", "John", "Peter", "Paul", "David", "Stacey"]

Languages like Python allow for this automatically without much effort from the programmer, however, other languages like C require you to specify the size of a variable upfront more often than not.

Most languages like Python, have something called “Garbage collection”. Now, what this basically means is that the programming language will watch your variables and automatically delete the memory they occupy whenever that variable is no longer needed (known as going out of scope).

Garbage collection is often not available in some languages like C and C++; thus, as a programmer, you have to manually delete variables (or deallocate memory) when they are no longer needed and carefully create variables cognizant of the fact that you must take up as little memory as possible.

This is also why languages like C are used in game development, hardware drivers, and so on, because by manually managing memory, you can optimize your program to use as little RAM as possible and also deallocate memory as quickly as possible.

Since the garbage collection process itself eats up some memory and may not clear memory quickly enough, languages like Python are often used in web development and other environments where the code runs on bulky servers with lots of RAM, thus the need to minimize memory usage isn’t as important.

In summary, a variable is a box in memory that we use in programming languages to store information. Variables can store a wide variety of information, and each box can be of varying sizes depending on the type of variable.

Ultimately, each variable is just a grouping of bytes in memory. The variable can be made up of any number of Bytes (very similar to how we put 8 bits together to make one Byte, we put x number of Bytes together to make a variable).

Primitive Data Types

Okay, so we learnt that in programming languages we use a variable, which essentially is a box to put data in. We also know that variables can hold a wide variety of information.

The problem is that programming is precise; you want to be as precise as possible. You don’t want to mix numbers and letters willy-nilly. Some languages, like PHP and Python, are a bit flexible in this regard; they are what we call dynamically typed languages.

In Python, this is valid (although never a good idea):

my_name = "Billy"
my_name = 123

Now, looking at the code carefully. I created a variable “my_name” and then put the word “Billy” inside that box, then in the very next line, I replaced “Billy” with 123. Python allows this because it doesn’t enforce types by default.

Can you imagine working on a large financial system, and somebody mistakenly assigns text to a variable:

account_balance=500
account_balance="500"

The problem is that they may look like the same value, 500, but actually, they are not. See what happens when I try to update the account balance:

>>> account_balance="500"
>>> account_balance+1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
>>>

Since “500” in quotes is actually a string (a chain of characters), Python throws an error. Saying: Wait a minute! I cannot add 1 to the word “500”. “500’ is not a number!

In some languages like Golang, TypeScript, C#, etc, doing something like the above will just not compile. Here’s a simple Go example:

package main

import "fmt"

func main() {
    var accountBalance int = 1
    fmt.Println(accountBalance)
}

Don’t worry so much about the syntax, such as “package”, “import”, “func”, etc I want you to zone in on this line:

var accountBalance int = 1

💡 The “var” keyword simply tells the Go compiler that you are making a new variable named “accountBalance”.

You will notice the int keyword. This is known as a primitive data type. The int data type tells the Golang compiler that this box in memory can only hold numbers, and more specifically, an integer. So when I do something like this, it will fail to compile:

package main

import "fmt"

func main() {
    var accountBalance int = 1
    accountBalance = "pokemon"
    fmt.Println(accountBalance)
}

The error:

➜  test go run main.go
# command-line-arguments
./main.go:7:19: cannot use "pokemon" (untyped string constant) as int value in assignment

Languages like Golang are known as “statically typed” languages.

Essentially, data types allow us to categorize variables so that we can store information in a structured way. The goal is to separate information based on different characteristics, such as integers (whole numbers), strings (text), floating-point numbers (decimals), and other distinct types.

💡 In the real world, you can think of data types as classifying different pieces of clothing. Just as we categorize items as "boots," "hats," or "shorts" based on their distinct characteristics and purposes, data types help us organize different kinds of information based on their unique properties and how they can be used.

Different languages have slight variations of these primitive data types, but in general, they mostly fall into the following categories:

  • Char - a single character like ‘A’.

  • String - a string of characters like “Hello”.

  • Byte - we already know this one.

  • Boolean - true or false

  • Decimal number - so basically similar to money, e.g., 120.99

  • Float - similar to Decimals, except they are not as precise

  • Integers - these are whole numbers 1,2,3,4,5, and can be negative as well -1,-2,-3. You also get variations in size, int, int64, and so on.

There’s way more to primitive data types than this simple article can cover, but hopefully, this is enough of a starting point for you to build upon.

Collections and dictionaries

Okay, so we learnt about variables, which are boxes in memory that you can put information into, and we learnt that each variable can have a type as well, like integers, strings, booleans, etc (primitive types).

In addition to these primitive types, variables can also hold more complex data types such as objects, lists, dictionaries, tuples, and more. Usually, complex data types are made up of one or more of the primitive types.

Let’s look at 2 of the most common types, i.e., lists and dictionaries. A list, as the name suggests, is a type that can hold a list of items:

shopping_list = ["eggs", "milk", "butter"]

Using Python, we created a “shopping_list” variable, which is a list of 3 items. Each list item in this case is of a primitive string type, however, the type can be just about any of the other types including a complex type.

In programming, lists are very handy and used in just about every program. Some examples:

  • In card games, you can use a list to store the deck of 52 cards.

  • In e-commerce, A list can store all items in the user’s shopping basket.

  • In a website’s navigation bar, a list can be used to store links to the relevant pages.

Unlike the primitive data types, a list can hold multiple values (usually these values are of the same primitive type, but not always), which makes it perfect for storing related items like products in a shopping cart.

In other languages, lists are also referred to as “arrays”; however, arrays can also have other features not supported by a simple list. So while the data type is similar, it’s not always exactly the same type.

For example, in JavaScript, arrays are the same as Python lists:

let shoppingArray = ["eggs", "milk", "butter"];

However, in PHP, while the type is called “array”, it’s much more powerful than a simple list since it also has features of the “dictionary” data type.

$shoppingArray = ["eggs", "milk", "butter"];
$personArray = ["name" => "Kevin", "surname" => "Naidoo"];

Lists or Arrays are usually zero-indexed, meaning that when we create the Python shopping list, under the hood, the language is assigning each item a position in the list:

💡 The # character in Python is a comment, meaning that the interpreter will ignore this. It’s merely there to help programmers communicate extra information to other programmers.

shopping_list = ["eggs", "milk", "butter"]

# Postions
# 0 => eggs
# 1 => milk
# 2 => butter

print(shopping_list[0])  # Will print eggs
print(shopping_list[1])  # Will print milk

The number we’re accessing above to print each item is known as an “index” and basically points to the position of the item in the list from left to right. Where the furthest position to the left is zero, and you keep adding 1 to the index as you move further right.

Moving backwards:

shopping_list = ["eggs", "milk", "butter"]

# Postions
# -3 => eggs
# -2 => milk
# -1 => butter

print(shopping_list[-1])  # Will print butter
print(shopping_list[-2])  # Will print milk

When moving backwards, the index starts from -1 and you add -1 to the index each time you move towards the left. The farthest item on the left when going backwards will be -3 in this case, it’s basically total_items * -1.

It’s not common to move backwards, so 99% of the time, you use this approach to simply get the last item when you don’t know the size of the list.

For example, in a deck of 52 cards, you may play some cards into a discard pile. Now, to access the last card in the deck, you can’t simply use cards[51]. Unless you count the cards in the deck again, you have no idea how many cards remain in the main deck.

By using cards[-1] This will always point to the last item in the deck so long as you have at least one card. Thus, you can dynamically always get the last item without having to constantly recount the deck.

Okay, so now we know that a list contains multiple items and each item is assigned a numerical position starting from 0. This data type is great if you don’t want to label the items, but what if you need to label the items?

For example, in your app, you have a dropdown asking users to select their country. You don’t want to manually type out each option by hand, so behind the scenes, you use a Python list populated from a database table to build an HTML dropdown:

# This data will be filled from the DB, just showing two values as an example.
countries = ["za", "us"]
<select>
     <option value="za">za</option>
      <option value="us">us</option>
</select>

The above is a simple HTML dropdown that will allow the user to select their country preference. The problem is, the user might not know their country code, and it’s far easier to select the full country name instead.

In the case of our dropdown, the server gets the value from the value field, it does not care about the label you see inside the <option> tags. In our Python code, we can therefore change the list into a dictionary (also known as a map in other languages). By doing so, we can set a custom index for each item, which will become the value set for the value field in our HTML.

Here’s how to make a dictionary:

# You can also put these on one line like a list, I did it this way for readability.
countries = {
   "za": "South Africa",
   "us": "United States",
   "uk":"United Kingdom"
}

A dictionary is very similar to a list, but as you can see, instead of 0,1,2,3 for the index, we set a custom index for each item, which is known as a key. The key will be of type string and serves as a label to better identify that piece of data.

Now, we can modify our dropdown to use the dictionary, so the result should be:

<select>
     <option value="za">South Africa</option>
      <option value="us">United States</option>
       <option value="uk">United Kingdom</option>
</select>

A dictionary, therefore, is much more powerful; not only can you store related information together, but you can also label data and build many interesting entities, like, for example, if you want to store information about a book: “The Pragmatic Programmer”.

the_book = [
   "The Pragmatic Programmer",
   "Journeyman to Master",
    1999, 
    "Pearson Education",
    352,
    9780132119177
]

We have 6 items, it’s kind of easy to guess what they are, but imagine if we had 20 items? This becomes really cumbersome. Instead, we can use a dictionary:

the_book = {
   "title": "The Pragmatic Programmer",
   "subtitle": "Journeyman to Master",
    "Year Published": 1999, 
    "Publisher": "Pearson Education",
    "Number of pages": 352,
    "Barcode / ISBN": 9780132119177
}

Looking at the second item, it’s far easier to identify what each data point means just by using the dictionary’s key. When we want to print an item, we can do so in a similar way to that of lists, by using the key instead of a numerical position:

print(the_book['title']) # The Pragmatic Programmer
print(the_book['Year Published']) # 1999

Conculsion

In this article, we learned about one of the most fundamental concepts in computer programming, i.e., data. We started at the very heart of the computer to understand how binary numbers represent electrical signals in transistors that allow the current to flow or prevent the current from flowing in a particular direction.

We then built upon this knowledge to learn about Bytes , which is a fundamental “Lego block” of modern computing. We even learnt some math, and further expanded into programmatic concepts like compilers, variables, data types, and more.

We’ve seen a little sneak peek into Python, Golang, and other languages.

All in all, this was a fun article to write, it allowed me to refresh some of these concepts I learned many many years ago. I hope that this was an ideal primer for you, to introduce you to these important fundamentals and help you grow as a developer.

Use this as a springboard into the world of programming; I merely got your feet wet, but to become a good programmer and have a long-lasting career in the industry, you must keep learning and constantly dig deeper.

Happy coding! I’m planning on more content like this that dives deeper into the engineering aspects of programming, so please join the newsletter or check back soon.

Thank you so much for reading 🙏

Cheers 👋

1
Subscribe to my newsletter

Read articles from Kevin Naidoo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kevin Naidoo
Kevin Naidoo

I am a South African-born tech leader with 15+ years of experience in software development including Linux servers and machine learning. My passion is web development and teaching. I often love experimenting with emerging technologies and use this blog as an outlet to share my knowledge and adventures. Learn about Python, Linux servers, SQL, Golang, SaaS, PHP, Machine Learning, and loads more.