8 Core Principles of Computer Science
Sometimes I wonder what computer science is and sometimes the answer is not obvious. Despite the years of studying and teaching, it can be easy to lose track of the core principles of the field. This story serves two purposes then. Foremost, to share what I believe to be the 8 core principles of computer science. Second, to serve as a reminder list. Of course, neither case is complete without applied examples. Let’s build out the 8 core principles using a video game character.
Abstraction: Abstraction is the process of reducing the complexity of a system by focusing on the high-level view and ignoring specific details. This allows us to manage and reason about complex systems. For example, when programming, we often use functions or methods to encapsulate tasks.
class GameCharacter:
def __init__(self, health=100, strength=10):
self.health = health
self.strength = strength
def attack(self, other_character):
other_character.health -= self.strength
print(f"Attacked other character for {self.strength} damage")
def heal(self, amount):
self.health += amount
print(f"Healed for {amount} health points")
def check_health(self):
print(f"Current health: {self.health}")
return self.health
# Create game characters
hero = GameCharacter(health=120, strength=15)
monster = GameCharacter(health=200, strength=20)
# Hero attacks monster
hero.attack(monster)
# Monster attacks hero
monster.attack(hero)
# Hero heals
hero.heal(30)
# Check health
hero.check_health()
monster.check_health()In this example, GameCharacter is an abstraction of a character in a video game. The attributes health and strength define the state of the character, while the methods attack, heal, and check_health define the actions that a character can perform.
These methods hide the details of how the actions are performed, such as how the attack method reduces the other character's health, or how the heal method increases the character's own health. This encapsulation of details is a key aspect of abstraction. It allows the game characters to be manipulated at a high level, without needing to know the details of how the characters are implemented. It simplifies our mental model of the system, allowing us to focus on the important high-level behaviors rather than the low-level details.
Decomposition: This involves breaking down a complex problem or system into smaller, more manageable parts. Decomposition is used extensively in areas such as software engineering (breaking down a large software system into modules or components) and algorithm design (breaking down a problem into simpler sub-problems).
class GameCharacter:
def __init__(self, health=100, strength=10):
self.health = health
self.strength = strength
def attack(self, other_character):
other_character.health -= self.strength
print(f"Attacked other character for {self.strength} damage")
def heal(self, amount):
self.health += amount
print(f"Healed for {amount} health points")
def check_health(self):
print(f"Current health: {self.health}")
return self.health
def special_attack(self, other_character):
# Step 1: Perform a normal attack
self.attack(other_character)
# Step 2: Heal self by half the strength
self.heal(self.strength / 2)
# Create game characters
hero = GameCharacter(health=120, strength=15)
monster = GameCharacter(health=200, strength=20)
# Hero performs special attack on monster
hero.special_attack(monster)
# Check health
hero.check_health()
monster.check_health()In this example, the special_attack method represents a more complex operation, but it's been decomposed into two simpler operations: a regular attack followed by a heal. This decomposition makes the special_attack operation much easier to understand and implement.
Algorithmic Thinking: An algorithm is a step-by-step procedure for solving a problem or achieving a goal. The development and analysis of algorithms is a fundamental part of computer science, as it’s how we create effective and efficient software.
class GameCharacter:
def __init__(self, health=100, strength=10):
self.health = health
self.strength = strength
def attack(self, other_character):
other_character.health -= self.strength
print(f"Attacked other character for {self.strength} damage")
def heal(self, amount):
self.health += amount
print(f"Healed for {amount} health points")
def check_health(self):
print(f"Current health: {self.health}")
return self.health
def defend_and_heal(self, other_character, health_threshold=30):
# Step 1: Check current health
if self.check_health() > health_threshold:
# Step 2: If health is above threshold, attack
self.attack(other_character)
else:
# Step 3: If health is below or equal to threshold, heal
self.heal(self.strength)
# Create game characters
hero = GameCharacter(health=120, strength=15)
monster = GameCharacter(health=200, strength=20)
# Hero and monster fight
while hero.check_health() > 0 and monster.check_health() > 0:
hero.defend_and_heal(monster)
monster.defend_and_heal(hero)
# Check final health
hero.check_health()
monster.check_health()In this code, the defend_and_heal method follows a clear algorithm. We first check the health. Then, we decide to attack or heal based on that health. Last, we perform the chosen action. This method could be used in the game to automate the actions of the characters based on their current health.
Data Representation and Processing: Understanding how data is represented, stored, and processed is another key principle. This includes understanding data structures (like arrays, linked lists, trees), databases, and how data is stored and retrieved.
class GameCharacter:
def __init__(self, health=100, strength=10, name=""):
self.health = health
self.strength = strength
self.name = name
def attack(self, other_character):
other_character.health -= self.strength
print(f"{self.name} attacked {other_character.name} for {self.strength} damage")
def heal(self, amount):
self.health += amount
print(f"{self.name} healed for {amount} health points")
def check_health(self):
print(f"{self.name} current health: {self.health}")
return self.health
def defend_and_heal(self, other_character, health_threshold=30):
if self.check_health() > health_threshold:
self.attack(other_character)
else:
self.heal(self.strength)
class Game:
def __init__(self):
self.characters = []
def add_character(self, character):
self.characters.append(character)
def start_fight(self):
while all(character.check_health() > 0 for character in self.characters):
for i in range(len(self.characters)):
attacker = self.characters[i]
defender = self.characters[(i+1)%len(self.characters)] # Attack the next character in the list
attacker.defend_and_heal(defender)
# Announce the game results
for character in self.characters:
if character.check_health() > 0:
print(f"{character.name} is victorious!")
# Create game characters
hero = GameCharacter(health=120, strength=15, name="Hero")
monster = GameCharacter(health=200, strength=20, name="Monster")
# Create a game
game = Game()
# Add characters to the game
game.add_character(hero)
game.add_character(monster)
# Start the fight
game.start_fight()In this example, the Game class represents and manages the game data. There is a list of GameCharacter objects stored in the characters attribute. The add_character method allows us to add characters to the game, and the start_fight method processes this data by orchestrating a fight between the characters. This is a basic example of data representation (the characters list) and data processing (the start_fight method).
Computational Thinking: This is a way of solving problems, designing systems, and understanding human behavior that draws on concepts from computer science. It involves making use of algorithmic thinking, decomposition, abstraction, and debugging, as well as understanding the capabilities and limitations of computers. It is a general approach that produces specific outcomes.
class GameCharacter:
def __init__(self, health=100, strength=10, name=""):
self.health = health
self.strength = strength
self.name = name
self.victory_count = 0
self.level = 1
def attack(self, other_character):
other_character.health -= self.strength
print(f"{self.name} attacked {other_character.name} for {self.strength} damage")
def heal(self, amount):
self.health += amount
print(f"{self.name} healed for {amount} health points")
def check_health(self):
print(f"{self.name} current health: {self.health}")
return self.health
def defend_and_heal(self, other_character, health_threshold=30):
if self.check_health() > health_threshold:
self.attack(other_character)
else:
self.heal(self.strength)
def level_up(self):
if self.victory_count >= 3: # Level up every 3 victories
self.level += 1
self.strength += 5 # Increase strength by 5 points each level
self.victory_count = 0 # Reset victory count
print(f"{self.name} leveled up! Now at level {self.level} with strength {self.strength}")
class Game:
def __init__(self):
self.characters = []
def add_character(self, character):
self.characters.append(character)
def start_fight(self):
while all(character.check_health() > 0 for character in self.characters):
for i in range(len(self.characters)):
attacker = self.characters[i]
defender = self.characters[(i+1)%len(self.characters)] # Attack the next character in the list
attacker.defend_and_heal(defender)
# After the fight, update the game results
for character in self.characters:
if character.check_health() > 0:
character.victory_count += 1
character.level_up()
print(f"{character.name} is victorious!")
# Create game characters
hero = GameCharacter(health=120, strength=15, name="Hero")
monster = GameCharacter(health=200, strength=20, name="Monster")
# Create a game
game = Game()
# Add characters to the game
game.add_character(hero)
game.add_character(monster)
# Start the fight
game.start_fight()The computational thinking comes into play when we broke down the problem of leveling up into smaller problems (counting victories, checking for level up, updating level and strength). We used algorithmic thinking to solve these smaller problems. The level_up method encapsulates the logic for leveling up, making it easier to understand and modify if needed.
Logic and Reasoning: Logical reasoning is used to write programs, design algorithms, and understand how systems operate. This includes understanding concepts from discrete mathematics, such as propositional logic, set theory, and graph theory. We can pinpoint where in our running example logic and reasoning are employed.
- Algorithmic logic: The methods inside our
GameCharacterclass, such asattack,heal,check_health, anddefend_and_heal, all use algorithmic logic. They define a series of steps and conditions that need to be executed or checked in order to perform their respective actions. For example, indefend_and_heal, there's a condition that checks if the character's health is above a certain threshold. If it is, the character attacks; otherwise, it heals. This is a simple form of logic and reasoning that's ubiquitous in programming. - Game loop logic: The
start_fightmethod in theGameclass contains the game loop, which is a common construct in game programming. This loop continues as long as all characters have health above 0. This uses logical reasoning to determine when the game should continue and when it should stop. - Level-up logic: The
level_upmethod uses logical reasoning to check if a character's victory count has reached a certain threshold and, if so, increments the character's level, increases the character's strength, and resets the victory count. - Conditional logic and control flow: The
ifstatements represent conditional logic. The actions taken by the program (whether to attack or heal, whether to level up or not) are determined by the logical conditions specified in theseifstatements. - Data logic: The structure and manipulation of data also involves logic. In our
Gameclass, we logically group together relatedGameCharacterobjects into a list. Theadd_characterandstart_fightmethods involve logic for manipulating this data.
System Design and Architecture: This involves understanding the basic building blocks of computers and systems, including understanding hardware (like CPUs, RAM, and hard drives), operating systems, networks, and more.
- Modularity: Our code is divided into two classes:
GameCharacterandGame. This makes the code modular and organized, with each class having its own responsibilities.GameCharactermanages the properties and actions of individual characters, whileGamemanages the overall game state and controls the game loop. - Encapsulation: We’ve used encapsulation to bundle data and methods that operate on that data within our classes. For example,
GameCharacterencapsulates data likehealth,strength,name, andvictory_count, and methods likeattack,heal, andlevel_upthat operate on this data. - Abstraction: We’ve used abstraction to hide the complexity of certain operations. For example, a complex operation like a special attack that involves both attacking and healing is abstracted into a single method
defend_and_heal. - Data Structure Design: The choice to represent a collection of
GameCharacterobjects as a list in theGameclass is a design decision that affects how we structure and process our game data. - Responsibility Distribution: We’ve also made decisions about where different responsibilities should lie. For example, the logic for leveling up a character is placed in the
GameCharacterclass, since it's closely related to the internal state of a character. - Scalability: The design of this code allows for easy expansion and scalability. New actions, characters, or game mechanics can be added by extending the
GameCharacterclass, and theGameclass can be extended to manage more complex game states or multiple rounds of fights.
Efficiency and Performance: Understanding how to make software and hardware perform efficiently is crucial. This can involve algorithm design and analysis, understanding time and space complexity, and considering the physical constraints of the hardware. After all, we can intend to design and implement efficient, performant systems but without verification we actually would not know for certain. Enter the unit test framework.
import unittest
class TestGameCharacter(unittest.TestCase):
def setUp(self):
self.hero = GameCharacter(health=120, strength=15, name="Hero")
self.monster = GameCharacter(health=200, strength=20, name="Monster")
def test_attack(self):
self.hero.attack(self.monster)
self.assertEqual(self.monster.health, 185) # Monster's health should be reduced by hero's strength
def test_heal(self):
self.hero.health = 50
self.hero.heal(30)
self.assertEqual(self.hero.health, 80) # Hero's health should be increased by 30
def test_level_up(self):
for _ in range(3):
self.hero.victory_count += 1
self.hero.level_up()
self.assertEqual(self.hero.level, 2) # Hero's level should be increased
self.assertEqual(self.hero.strength, 20) # Hero's strength should be increased by 5
self.assertEqual(self.hero.victory_count, 0) # Hero's victory count should be reset
if __name__ == '__main__':
unittest.main()This TestGameCharacter class extends the unittest.TestCase class, which provides a framework for creating and running tests. Each method in this class that starts with "test_" is a separate test. In the setUp method, we create the game characters that we will use in each test.
If we wanted to optimize our GameCharacter methods for better performance, we could run these tests before and after making our changes to ensure that the functionality of these methods remains the same. We can also run specific tests like I outlined here.
These are the 8 core principles of computer science in my opinion. Now, what I like so much about these principles is all eight have both a theoretical and applied foundation. The examples I’ve used in this story straddle the line between theory and application. I admit the code is simple. Yet, each I say demonstrates the concept well enough for us to embark on deeper study. And study deeper we shall. Stay tuned to this space as we construct more advanced examples for each principle.
If you appreciate this story, here are three actions you can take right now to support my work:
1. Give the story a CLAP 👏 and leave a COMMENT 📫 with your thoughts
2. FOLLOW me to get notified of new stories ⏰
3. SHARE and recommend this story on your social media 🐦





