CodingNic

Final Capstone Project

Refactoring and Structure

Final Capstone Project 60 min read

Refactoring and Structure

Refactoring and Structure

Your application now works.

In the past few lessons, you have actually been writing well-structured code already — but you may not have noticed why.

In this lesson, you will:

  • review the structural patterns your code uses
  • understand why each one matters
  • spot opportunities to clean up further
  • prepare your codebase for testing

Goal of This Lesson

By the end of this lesson, you will:

  • understand the patterns that make your code maintainable
  • recognize separation of concerns in your project
  • identify and clean up any remaining issues
  • leave your codebase ready for tests

Pattern 1: Separation of Responsibilities

Your structure follows this rule:

text
UI → calls → services → talks to → database

Rules

  • UI never contains SQL
  • UI never contains business logic
  • Services never contain UI code

Open any service file (e.g. task_service.py). You will not find a single tk or Listbox reference.

Open app_ui.py. You will not find a single cursor.execute(...).

This is intentional. Each layer only knows about the layer below it.


Pattern 2: Centralized Theme

In app_ui.py, all colors live in one dictionary:

python
THEME = {
    "bg":            "#f3f4f6",
    "card":          "#ffffff",
    "primary":       "#2563eb",
    # ...
}

Why this matters

Imagine you decide to change your primary color from blue to purple.

  • Without THEME: you search the file for every "#2563eb" and hope you find them all
  • With THEME: you change one line

Same logic for fonts. Constants like FONT_TITLE, FONT_HEAD, FONT_LABEL exist for the same reason.


Pattern 3: Reusable Helpers

You did not write three separate “stat card” code blocks for tasks, completed, and expenses.

You wrote one helper:

python
def _build_stat_card(parent, label, value, accent_bg, accent_fg):
    ...
    return {"card": card, "value": value_lbl}

And called it three times.

Other helpers you have

  • _styled_button(...) — every button in the app
  • _build_panel(...) — every panel in the dashboard
  • _clear(...) — every screen transition

The rule

If you find yourself writing similar code more than twice, extract a helper.


Pattern 4: Section Builders

build_task_section and build_expense_section are not just helpers — they are section builders.

Each one:

  • takes a parent widget to build into
  • takes a user_id to know whose data to load
  • takes an optional on_change callback for the dashboard to react to changes

This means the dashboard does not need to know how tasks work internally.

It just says: “build a task section here, and call refresh_summary when something changes.”


Pattern 5: The on_change Callback

Look at how the dashboard wires the sections:

python
build_task_section(task_panel["body"], user_id, on_change=refresh_summary)
build_expense_section(expense_panel["body"], user_id, on_change=refresh_summary)

The section does not import refresh_summary.

The dashboard does not reach inside the section.

Instead: the dashboard hands the section a function to call.

This is called dependency injection, and it is one of the most important patterns in software.

It keeps modules decoupled — easy to test, easy to move, easy to change.


Pattern 6: Returning Dicts from Builders

Notice how _build_stat_card and _build_panel return dictionaries:

python
return {"card": card, "value": value_lbl}
return {"card": card, "body": body}

This lets the caller access multiple parts of what was built.

For stat cards: the dashboard places the card and updates the value label later.

For panels: the dashboard places the card and fills the body with section content.

This is cleaner than returning tuples — result["card"] is more readable than result[0].


Step 1: Cleanup Pass

Open app_ui.py and check each of these:

☐ Are there any hard-coded colors outside THEME?

Search for "#" in your file. Every hex color should come from THEME.

☐ Are there any direct tk.Button calls?

You should be using _styled_button(...). Search for tk.Button — there should be zero results.

☐ Are there any database calls in app_ui.py?

Search for cursor, execute, commit. There should be zero results.

☐ Are functions getting too long?

If show_dashboard is over ~50 lines, look for chunks to extract into helpers.


Step 2: Naming Check

Names should describe what something is, not what type it is.

Bad

python
data = get_dashboard_data(user_id)
frame = tk.Frame(window)

Good

python
dashboard_data = get_dashboard_data(user_id)
content_frame = tk.Frame(window)

Look through your file for variables named data, frame, result, temp, etc. and rename them.


Step 3: Service Cleanliness

Open each service file and check:

  • ☐ Only contains database logic
  • ☐ Returns clean data (lists, dicts, simple values)
  • ☐ Does not print
  • ☐ Does not import anything from app/ui/

If any service imports from the UI layer, that is a serious problem — fix it before moving on.


Step 4: Folder Structure Check

Your project should look like:

text
productivity_app/
    app/
        services/
            database.py
            user_service.py
            task_service.py
            expense_service.py
            dashboard_service.py
        ui/
            app_ui.py
    tests/
    main.py

If anything is in the wrong folder, move it now.


What You Achieved

Your code already demonstrates:

  • separation of concerns
  • centralized theming
  • reusable helpers
  • section builders
  • dependency injection via callbacks
  • clean naming

These are not “advanced” patterns reserved for senior developers.

They are normal, expected practices in any real codebase.


Important Mindset

Refactoring is not optional in real projects.

It is part of development.

The reason your code is clean now is because the lessons were structured to teach the patterns gradually — but in your own future projects, you will need to refactor as you go.

The signal is always: “Am I about to write this same code a third time?”

If yes, stop and extract a helper.


Why This Step Matters

This is what distinguishes:

text
beginner code   →   professional code

Not the language. Not the framework. The structure.


Summary

You reviewed the structural patterns your code already uses, cleaned up any remaining issues, and confirmed your project is ready for testing. You now understand why the code is organized the way it is — not just how.