Skip to content

Code Refactor

Nathan Turley edited this page Oct 21, 2025 · 1 revision

Firestore Data Normalization Refactor

Overview

This refactor addresses inconsistent Firestore data handling across the Lost & Found application by centralizing normalization logic into a dedicated service. Previously, different components handled Firestore Timestamps, field name variations, and data transformations in their own ways, leading to duplicated code and inconsistent patterns.

What Was Changed

Created Central Normalization Service

A new services/firestoreNormalizer.js file (230 lines) consolidates all Firestore data transformation logic. It provides dedicated functions for each document type:

normalizeItem() - Handles items with field reconciliation (imageURL/imageUrl, type/category, status/kind)

normalizeMessage() - Processes conversation messages

normalizeConversation() - Handles conversation metadata

normalizeUser() - Standardizes user profile data

normalizeTimestamp() - Converts 6+ different timestamp formats to ISO strings

extractDate() - Coalesces multiple date field names (date, createdAt, created_at, timestamp, dateCreated)

Refactored Existing Components

utils.js - The existing normalizeFirestoreItem() function was simplified from 90+ lines to 40 lines by delegating core normalization to the service while retaining UI-specific logic like reporter information.

ProfilePage.js - Replaced custom coalesceDate() helper (checking 5 date fields manually) with the service's extractDate() function, eliminating duplicate date-handling logic.

Messages.js - Removed inline timestamp processing scattered throughout the component. The fetchItemData(), enrichConversations(), and message rendering now use normalizeItem(), normalizeConversation(), and normalizeMessage() respectively. Timestamp sorting logic was simplified from checking .seconds properties to using consistent ISO strings.

Feed.js - No changes required; already uses normalizeFirestoreItem() which now delegates to the service, demonstrating backward compatibility.

How Maintainability Improved

Easier Schema Evolution

Example: Adding a lastUpdated field to items.

Before: Update 5+ files (utils.js date normalization, ProfilePage.js coalesceDate, ItemDetail.js display logic, Feed.js query transformation, plus 3+ test files).

After: Add one line to normalizeItem():

lastUpdated: normalizeTimestamp(data.lastUpdated)

All components automatically receive the new field through existing normalization calls.

Reduced Code Duplication

Eliminated ~50 lines of repeated timestamp handling code. Field name reconciliation (imageURL vs imageUrl, type vs category, status vs kind) now happens in one place instead of being scattered across components.

Better Debugging

All normalized objects preserve original data in a _raw field, allowing developers to inspect what Firestore returned versus what was normalized, making data-related bugs easier to diagnose.

Improved Testing

Instead of mocking complex Firestore Timestamp objects in every component test, tests can now mock the normalizer service. The centralized test suite serves as living documentation of how all data transformations work.

Conclusion

This refactor transforms scattered, inconsistent data handling into a maintainable, well-tested service without changing any user-facing functionality. Future Firestore schema changes now require updates in one location, and the consistent data shapes across the application reduce bugs and improve code clarity. The refactor demonstrates how centralized normalization improves long-term maintainability in full-stack applications dealing with database abstraction layers.

Clone this wiki locally