Get Down With Object Oriented Programming II: Object Oriented Programming All Around Us
- Allison Higgins
- 2 hours ago
- 8 min read

On my decade-long path to becoming a senior software engineer, I have been asked an astounding range of technical interview questions, in a variety of formats. I’ve done the take home assignments, brand name assessments, the panel vs me alone, and my personal favorite format, the technical conversation where I can share my experience and expertise, and it can be evaluated truthfully, based on my responses and follow up questions or suggestions. Some of these interviews and questions have been intense, but with practice and due diligence, I’ve built a routine to quickly switch from “job focused” engineer to “interview ready” engineer in approximately 6-8 weeks. While building this routine, I have repeatedly noticed that knowledge and mastery of data structures, algorithms, and how to apply them to object oriented programming consistently differentiates a candidate in a sea of applicants.
In a former role, I worked with an internal language and building platform that closely resembled Java and the Java Virtual Machine. As part of the interview for this role, I had to demonstrate a deep understanding of object oriented programming principles and unified modeling language diagrams. In my initial recruiter screening, I recalled a slight sense of panic as I was told that the interview would mostly consist of concepts I hadn’t reviewed or studied since undergrad. After some strategizing, I realized that I had to:
Refresh and practice these fundamentals through videos, examples, practice scenarios, and creating my own study guide
Recall, use, and justify the application of object oriented programming fundamentals that were not necessarily required for my past full stack/front end development roles
This blog will cover
Why does Object Oriented Programming Matter?
Key Terms and Definitions
Implementing our Object Oriented Fundamentals to Make a School “fer” Wizards and Witches
Object Oriented Principles All Around Us
Again, why does this matter?
Resources For Practice
Why does Object Oriented Programming Matter?
There will always be a new, shiny technology that attracts a variety of investments and experts, but the underlying fundamentals and how to apply them will always be relevant. Understanding these principles eases the path to furthering your personal studies of data structures, algorithms, and eventually system design. These three are the core skills evaluated during a software engineer interview. These concepts are the foundations for building robust frontend/backend systems, data pipelines, and AI enablement, for any number of software needs across industries.
Key Terms and Definitions:
Object Oriented Programming (OOP)
Modeling a system as a collection of objects where each object represents some particular part of the system
Objects have functions/methods and data
Object provides a public interface to other code that wants to implement it, but its internal state is private
These are purposefully abstracted because the other parts of the system do not need to know about them
Inheritance
Allowing one class to inherit features from another, promoting reusability in code
also known as subclassing
Polymorphism
Objects of a different type can be accessed through the same interface
Each type can provide its own independent implementation of this interface
Encapsulation
Coupling data and methods into a single object to protect internal logic
Allows a dev to change the internal implementation of an object, without having to update all the code that uses it
Little firewall
Abstraction
Hiding complex details while exposing only necessary functionalities to external users
Data abstraction
Process abstraction
Difference between abstract classes and interfaces is that interfaces do not contain any method implementations, only the method signatures
Visibility can also be established using key keywords private, protected, and public
can also be indicated by an underscore
Let’s Implement our new OOP Knowledge to Build a school “fer” wizards and witches
We will start by modeling a school with objects representing students
Class name: Student
Attributes: name, house, and year
Actions: introduceToClass, introduceToFriends, castSpell
This definition lists the data and methods the student object has
Alone, our student class doesn’t do anything
This is the template to create a student, but to create an instance of a student, we must use a constructor
Usually the constructor is included with the class definition and has the same name as the class it’s in
Here we’d call it with the properties we set previously: name, house, and year
Now we can create several different students
Generation is indicated with the “new” key word
student Hermione = new Student(“Hermione”, Gryfindoor, 4);
Let’s Implement a method - introduceToClass
Hermione.introduceToClass();
But what if we tried ProfessorSnape.introduceToClass?
Immediate error because the object ProfessorSnape doesn’t exist in our school object model yet. Let’s fix it.
Student ProfessorSnape = new Student(“Professor Snape”, Slytherin, 18)
Professor Snape is NOT a student, so he would need a professor class for instantiation
Class name: Professor
Attributes: name, subject
Actions: introduceToClass
Does this look incredibly similar to the student class?
Addressing the commonality of student and professor classes
Both have attribute name and a method for introducing themselves
On a core level data wise, they are the same “kind” of object, just slightly different implementations
We can better express this with a superclass
Class name: Person
Attributes: name
Methods: introduceToClass()
To implement specific instances of person, such as student or professor, we use the key word extends
In OOP, extends, allows for use of custom properties and methods particular to the object you want to create
The method introduceToClass can also be customized in a student instance or a professor instances
Let’s implement a new constraint in our school universe:
"Students can only take advanced defense against the dark arts after year 4"
This new constraint can be defined specifically in the student class
If this constraint changes, for example, to require parental permission as well, we need to update this condition everywhere in our school universe where this check is performed
Better design to create a custom canStudy() method on student class that implements this logic in one place.
Object Oriented Programming All Around Us
JavaScript supports core object-oriented programming principles through its flexible and dynamic nature.
Abstraction: Achieved using functions, classes, and modules that hide complexity and expose only essential interfaces.
Encapsulation: Implemented through closures, which allow functions to retain access to variables from their parent scope even after that scope has finished executing.
Polymorphism: Enabled by method overriding and overloading, allowing objects to define different behaviors for the same interface.
Inheritance: Achieved via the prototype chain, where objects can delegate behavior to other objects. Unlike traditional class-based inheritance, JavaScript’s approach is delegation-based — objects can ask their “prototype” to perform tasks they don’t handle themselves.
JavaScript Closure Example:

makeFunction() defines a variable count and returns innerFunction.
Even after makeFunction() has finished running, innerFunction still “remembers” the variable count from its parent scope — this is the closure in action.
Each call to counter() updates and logs the preserved count value.
Python also supports object oriented programming principles despite being considered a functional language.
Abstraction: Python achieves abstraction using abstract base classes (ABCs) from the abc module.Abstract methods and properties define an interface that subclasses must implement, hiding unnecessary implementation details and focusing on essential behavior.
Encapsulation: Controlled access to class attributes through access specifiers (_protected, __private) and getter/setter methods. This ensures that internal data is shielded from direct external modification.
Polymorphism: Supports runtime polymorphism, where the same method name can exhibit different behaviors depending on the object calling it (e.g., method overriding).
Inheritance: Enables reusability and structure through different forms:
Single Inheritance: One child inherits from one parent.
Multiple Inheritance: A child inherits from multiple parents.
Multilevel Inheritance: A child inherits from a parent, which itself is a child of another class.
Hierarchical Inheritance: Multiple child classes inherit from a single parent.
Python Abstraction and Inheritance In-Depth with Examples
Abstraction
Animal is an abstract base class (inheriting from ABC).
The @abstractmethod decorator means any subclass must implement make_sound(), or else it can’t be instantiated.
This enforces a contract for all animals — every animal must define how it makes a sound.
Single Inheritance
Dog inherits from Animal → this is single inheritance (one parent, one child).
The attribute __name is encapsulated (made private with double underscores).
Access is controlled using getter (get_name) and setter (set_name) methods.
make_sound() is implemented (overriding the abstract method from Animal), showing polymorphism — the same method name can have different behaviors across subclasses.
Multiple Inheritance
GuardDog inherits from three classes: CanRun, CanBark, and Dog.
This is multiple inheritance — one class inherits from more than one parent.
As a result, GuardDog can:
Use run() from CanRun
Use bark() from CanBark
Use make_sound() and encapsulated methods from Dog
This allows GuardDog to combine behaviors from multiple sources — a hallmark of multiple inheritance.
Multilevel Inheritance
Puppy inherits from Dog, which inherits from Animal.
This is multilevel inheritance — a chain of inheritance across multiple levels.
Puppy overrides make_sound() again (now “Yip!”), showing runtime polymorphism — the version of the method that runs depends on the object’s actual type at runtime.
Hierarchal Inheritance
Both Dog and Cat inherit from the same parent (Animal).
This is hierarchical inheritance — one parent, multiple children.
Each subclass provides its own version of make_sound().
Although Rust isn’t traditionally classified as an object-oriented language, it implements many object oriented programming concepts in its own way.
Abstraction: Rust achieves abstraction primarily through generics and traits:
Generics allow code to be written for multiple data types without repetition.
Trait bounds specify what behaviors a type must implement, allowing for shared interfaces similar to abstract classes or interfaces in other languages.
Encapsulation: Rust uses modules and the pub keyword to control visibility:
By default, all items are private to their module.
The pub keyword explicitly exposes functions, structs, and methods to other parts of the program.
Implementation blocks (impl) define methods for types, similar to how classes encapsulate behavior in object oriented programming.
Inheritance: Rust doesn’t have traditional class inheritance. Instead, it encourages composition and trait-based behavior sharing.
The closest equivalent to inheritance is macros, which enable code reuse and pattern expansion across multiple types or modules — somewhat like metaprogramming templates.
Polymorphism: Rust supports bounded parametric polymorphism, meaning:
Functions and data structures can work with any type (T) as long as that type satisfies certain trait bounds.
This is polymorphism via traits, not class hierarchies — ensuring compile-time safety.
Macros and Metaprogramming in Rust
A macro in Rust is code that writes other code — a form of metaprogramming
The most common example is println!(), a function-like macro that expands to output code at compile time.
Macros allow Rust to implement powerful code reuse and abstraction patterns without runtime overhead.

Go is not a class-based object-oriented language like Java or Python, but it supports object oriented principles through its own unique design choices — emphasizing simplicity, composition, and interfaces rather than traditional inheritance.
Abstraction: In Go, interfaces provide abstraction. An interface defines a set of method signatures — any type that implements those methods automatically satisfies the interface, without explicitly declaring it. This enables flexible, decoupled design.
Encapsulation: Go controls visibility using capitalization. This replaces explicit access modifiers like private or public.
Identifiers (functions, methods, types) that start with an uppercase letter are exported (public).
Identifiers that start with a lowercase letter are unexported (private) to their package.
Inheritance (via Composition): Go does not support classical inheritance. Instead, it uses composition, where a struct contains another struct to reuse its fields and methods. This pattern is often described as “has-a” instead of “is-a” relationship.
Polymorphism: Go supports polymorphism through interfaces. Different types can implement the same interface and be used interchangeably where that interface is expected.
Structs in Go

Collection of members of different data types into a single variable
This is useful for grouping together data to create/store records
To access the members of a struct, use dot notation
Again Why Does this Matter
There will always be a new, shiny technology that attracts a variety of investments and experts, but the underlying fundamentals and how to apply them will always be relevant. Understanding these principles eases the path to furthering your personal studies of data structures, algorithms, and eventually system design. These three are the core skills evaluated during a software engineer interview — but more importantly, they are the same skills that form the backbone of everything we build in this field. Understanding object-oriented programming (OOP) fundamentals is not just an academic exercise; it’s the foundation for designing and maintaining robust systems — whether you’re architecting a frontend application, a backend service, a data pipeline, or an AI-driven platform. OOP principles such as abstraction, encapsulation, inheritance, and polymorphism enable engineers to write code that is modular, maintainable, and scalable across any domain. By mastering these concepts, engineers at any level — from junior developers to senior executives — can better navigate new technologies with confidence. The syntax and tools may change, but the mental models stay the same.
Resources for Practice
JavaScript
Python
Rust
Golang
General Programming
Comments