Chapter 38 Self-Assessment Quiz: Capstone Project
Test your understanding of the design decisions and implementation techniques used in the PennyWise 2.0 capstone project.
Section 1: Multiple Choice
Q1. The PennyWise 2.0 architecture separates code into five units. What is the primary benefit of this separation?
(a) It makes the program run faster because each unit compiles independently (b) It ensures that changes to one concern (e.g., database) do not require changes to another (e.g., UI) (c) Free Pascal requires every program to have at least five units (d) It reduces the total number of lines of code
Answer
(b) Separation of concerns means that each unit has a single, well-defined responsibility. If you change the database backend (e.g., switching from SQLite to PostgreSQL), onlyFinanceDB needs to change. The UI, business logic, and export modules remain untouched. This principle makes the software maintainable, testable, and extensible.
Q2. Why does TExpense inherit from TTransaction rather than being a standalone class?
(a) Because Pascal requires all classes to have a parent class (b) Because it saves memory by sharing field definitions (c) Because it models a real relationship — every expense IS a transaction — enabling polymorphic operations on any transaction (d) Because the database uses a single table for both types
Answer
(c) Inheritance models an "is-a" relationship. Every expense is a transaction, and every income entry is a transaction. This inheritance allows us to write procedures likeDisplayTransaction(T: TTransaction) that work with both expenses and income entries — polymorphism in action. While (d) is also true (we use single-table inheritance in the database), the class hierarchy was designed to model the domain, not to match the database.
Q3. The FinanceDB unit uses parameterized queries (ParamByName) rather than string concatenation to build SQL. Why?
(a) Parameterized queries run faster than concatenated strings (b) Parameterized queries prevent SQL injection attacks by treating parameters as data, never as code (c) Free Pascal does not support string concatenation in SQL queries (d) Parameterized queries automatically handle date formatting
Answer
(b) SQL injection is one of the most common security vulnerabilities in software that uses databases. If we built queries by concatenating user input (e.g.,'SELECT * FROM transactions WHERE category = ''' + UserInput + ''''), a malicious user could inject SQL code. Parameterized queries prevent this entirely because the database engine treats parameter values as data, never as executable SQL. This is a security practice that applies to every language and every database, not just Pascal and SQLite.
Q4. The TAutoSaveThread uses Synchronize to perform the actual database save. Why not save directly from the background thread?
(a) Free Pascal threads cannot access global variables
(b) The SQLite connection is not configured for thread-safe access, so database operations must run on the main thread
(c) Synchronize makes the save run faster
(d) Background threads in Free Pascal cannot create objects
Answer
(b) By default, SQLite connections are not thread-safe. OurTFinanceDatabase uses a single TSQLite3Connection that was created on the main thread. Accessing it from a background thread without synchronization would cause race conditions and data corruption. Synchronize schedules the save operation to run on the main thread's message loop, ensuring safe access. An alternative would be to configure SQLite for multi-threaded access (WAL mode + separate connections), but that adds complexity.
Q5. Which of the following is NOT a benefit of native compilation for PennyWise 2.0?
(a) The user does not need to install a runtime (Python, Java, .NET) (b) Startup time is fast because there is no interpreter or JIT compilation (c) The compiled binary is automatically cross-platform without recompilation (d) Memory usage is predictable because there is no garbage collector pausing execution
Answer
(c) Native compilation does NOT make the binary automatically cross-platform. A binary compiled for Windows will not run on Linux or macOS. What makes PennyWise cross-platform is the source code — it uses the LCL and SQLDB, which are cross-platform abstractions. The source code must be compiled separately for each target platform (or cross-compiled). The other three options are genuine benefits of native compilation.Q6. The TTransactionManager.ValidateAmount method is a class function. What does this mean?
(a) It can only be called on a TTransactionManager instance
(b) It can be called without creating a TTransactionManager instance, using the class name directly
(c) It runs in a separate thread for safety
(d) It is automatically called by the compiler before every amount assignment
Answer
(b) Aclass function belongs to the class itself, not to any particular instance. You call it as TTransactionManager.ValidateAmount(SomeAmount) without needing a TTransactionManager object. This is appropriate for validation methods that do not depend on any instance state — they are pure functions that take an input and return a boolean.
Q7. The database schema uses CREATE INDEX IF NOT EXISTS idx_trans_date ON transactions(date). What is the purpose of this index?
(a) It ensures that no two transactions can have the same date (b) It speeds up queries that filter or sort by date by allowing the database to locate rows without scanning the entire table (c) It automatically sorts the transactions table by date (d) It prevents invalid dates from being inserted
Answer
(b) A database index is like the index at the back of a textbook — it allows the database engine to quickly find rows matching a condition without scanning every row. Theidx_trans_date index speeds up queries like WHERE date >= '2026-03-01' AND date <= '2026-03-31', which PennyWise uses constantly for monthly reports. Without the index, SQLite would need to examine every row in the table — slow for 100,000+ transactions.
Q8. The unit tests in TestFinanceCore test FinanceCore without using FinanceDB or FinanceUI. What design principle makes this possible?
(a) Encapsulation — the tests cannot access private fields
(b) Polymorphism — the tests use mock objects
(c) Separation of concerns — FinanceCore has no dependencies on the database or UI
(d) Inheritance — the test class inherits from TTransactionManager
Answer
(c) BecauseFinanceCore does not use FinanceDB or FinanceUI in its uses clause, it can be compiled and tested in complete isolation. The tests create a TTransactionManager, add transactions, and verify that the business logic produces correct results — all without touching a database or drawing a pixel. This is the practical payoff of separating concerns at the unit level.
Section 2: Short Answer
Q9. Explain the "Validate-Persist-Display" pattern used in PennyWise's event handlers. Why is the order important? What would go wrong if you displayed before persisting?
Answer
The pattern is: (1) validate input, (2) persist the change to the database, (3) refresh the display. The order matters because:- Validate first: If input is invalid, we stop immediately and show an error — no change is made to the data or the display.
- Persist before display: If we refreshed the display first and then the database save failed (e.g., disk full), the UI would show data that was not actually saved. The user would think their transaction was recorded when it was not. By persisting first and only displaying after a successful save, we ensure the UI always reflects the actual state of the database.
Q10. Why does the PennyWise database schema store dates as TEXT in ISO 8601 format (YYYY-MM-DD) rather than as INTEGER (Unix timestamp) or REAL (Julian day)?
Answer
ISO 8601 text format has several advantages: (1) Human-readable — you can inspect the database with a SQLite browser and immediately understand the dates. (2) Sortable — ISO 8601 dates sort correctly as strings because the format is year-month-day. (3) Standard — every programming language and database tool understands ISO 8601. (4) No timezone ambiguity for date-only values. The tradeoff is slightly more storage space than an integer, but for a personal finance application, this is negligible.Q11. The capstone project includes three levels of testing: unit tests, integration tests, and manual tests. Give one example of a bug that each level would catch that the other two would not.
Answer
- Unit test catches: A calculation error in
TTransactionManager.GetTotalExpensesthat sums income instead of expenses. This is a logic error in pure business code — no database or UI involved. - Integration test catches: A SQL query in
TFinanceDatabase.GetCategoryTotalsthat uses the wrong date format, causing it to return no results even when transactions exist. The business logic is correct, but the database interaction is wrong. - Manual test catches: The chart is too small to read on a low-resolution screen, or the tab order of the entry form is confusing. These are usability issues that cannot be detected by automated tests.
Q12. If you wanted to replace SQLite with PostgreSQL in PennyWise, which units would need to change and which would remain untouched? Explain why.
Answer
OnlyFinanceDB would need to change — replacing TSQLite3Connection with TPQConnection (Free Pascal's PostgreSQL connector) and adjusting any SQLite-specific SQL syntax. The units FinanceCore, FinanceUI, FinanceExport, and FinanceSync would remain untouched because they never reference SQLite directly. FinanceCore defines the domain model, FinanceUI only talks to the manager, and FinanceExport reads from the manager. This is the separation of concerns in action — the database is an implementation detail hidden behind the TFinanceDatabase interface.