The Friction — Paper Trails & Human Memory
Renting out a fleet of vehicles by hand is an exercise in predictable human failure. Late fees get miscalculated on scrap paper, return inspections are forgotten, and damage claims are resolved by arguments rather than records. It’s what happens when a business attempts to run on human memory instead of a strict, mathematical system.
For our university Object-Oriented Programming (OOP) lab project at UET Taxila, three teammates and I decided to tackle this logistical chaos. We set out to design a shared console application that handles fleet tracking, sales, returns, dynamic billing, and a customer-facing trip planner.
The Architecture — Decoupled Base Blueprints
We split the application into logical segments — UI orchestration, data persistence, transactions, and input validation. The core architectural decision revolved around decoupling: using abstract base classes with pure virtual functions so that distinct vehicle types could evaluate their own pricing models while sharing a common interface.
"We chose simple file streams over database configurations. It was a deliberate trade-off: we wanted our limited 4-week window spent mastering C++ inheritance and SOLID principles, not debugging database connection strings."
Under the hood, Vehicle, User,
and Transaction served as the three
structural blueprints that the rest of the systems
integrated with.
UI Orchestration & Session Workflow"] AdminS["Admin Session"] CustS["Customer Session"] Eng["SearchEngine & TripPlanner"] AdminF["Admin Features
• Dashboard
• Fleet CRUD
• User Management"] Trans["Transactions Layer
• Rentals
• Sales
• Post-Return Inspections"] %% Connections Menu --> AdminS Menu --> CustS Menu --> Eng AdminS --> AdminF CustS --> Trans Eng --> Trans %% Assign Classes class Menu main; class AdminS,CustS,Eng sub; class AdminF,Trans feat;
Core Mechanics — State Inspections & Dynamic Rates
The application manages a single fleet shared between Admins and Customers. Vehicles fall into four categories: Economy, Luxury, SUV, and Van. To make the console application feel like a real utility, we focused on several detailed logic paths:
- Ligated Rental Rates: Renting longer costs less per day. 4–7 days triggers an automatic 10% discount, and 8 or more days grants a 20% discount.
-
Inspection Workflows: Returns go
through a rigorous logging phase rather than a flat
checklist. Condition metrics—mapped as
Good,Fair, orPoor—calculate damage surcharge fees (ranging from zero to double daily rates) and append them to the customer's final receipt. - Transaction Backbone: Renting and selling share a base class but behave differently enough that merging them into a single class would have violated single-responsibility principles.
Team Dynamics —VS Code Syncing & Class Agreements
Leading a small team through one shared codebase taught me that coordination is harder than coding. In the early days, we suffered from merge conflicts, broken builds, and files written against assumptions we hadn't actually agreed on yet.
"Most of what we called 'debugging' had nothing to do with syntax. It was about sequencing: aligning on the interfaces of shared classes before anybody starts writing code on top of them."
We also hit issues with user inputs crash-looping the console application (e.g. putting a string into an integer variable), which led us to build a robust, centralized input validation filter module early in the cycle rather than scattering checks across the code.
Retrospective — Replacing Text Files & Securing Logins
While flat text files served their purpose for our timeline, they are the first thing I would replace. One broken line in a raw file can currently corrupt data loading. In a real-world rebuild, I would integrate SQLite to gain ACID transaction guarantees and relational integrity. I would also add cryptographic password hashing (using bcrypt or argon2) to replace the current plaintext user logins.