The Problem
The Arizona Department of Education needed web forms for organizations to get reimbursed through federal USDA food programs — meals for impoverished children and adults.
These weren't simple forms. They had heavy conditional logic: fields appearing or hiding based on other answers, different input types (radio buttons, checkboxes, multiline text), validation rules that changed depending on context.
The standard approach — imperative show/hide callbacks scattered across jQuery handlers — would have been spaghetti. Every new conditional rule meant tracing callback chains and hoping you didn't break something else.
My Role
I designed this system entirely. The department had standardized on ASP.NET / jQuery / SQL Server, and I created an approach that worked within those constraints.
The Solution: Attribute-Based Form Definition
Instead of writing imperative logic, I made the data model the source of truth:
Custom C# Attributes
Each model property could be decorated with custom attributes that defined conditional evaluation logic (when to show/hide) and behavior (what input type, validation rules, etc).
Front-End: jQuery Behaviors
Custom ASP.NET components rendered the attributes as data-* attributes. jQuery observed these and applied show/hide animations, input behaviors, and client-side validation automatically.
Back-End: Same Validation
The same attributes drove server-side validation. No duplicate logic — if the attribute said a field was required under condition X, both client and server enforced it.
Why This Worked
- Single source of truth: Conditional logic lived in one place (the model attributes), not scattered across jQuery handlers
- Declarative over imperative: New fields meant adding attributes, not tracing callback chains
- Consistent validation: Front-end and back-end always agreed because they read the same definitions
- Predictable debugging: When something broke, it was either a mis-attributed property or a failed attribute implementation — known categories, not mystery callbacks
Tradeoffs
Initial Learning Curve
The pattern wasn't immediately obvious to developers who hadn't seen it. Understanding how attributes flowed into jQuery behaviors required ramping up on the system.
Debugging Complexity (Initially)
Early on, debugging required understanding the full stack. But once the mental model clicked, debugging became more predictable than scattered callbacks would have been.
Outcomes
The system was used across multiple forms for several USDA programs. Complex conditional logic was manageable. New developers could add fields by following the attribute patterns rather than reverse-engineering callback chains.
What I'd Do Differently
Better onboarding documentation. The pattern was powerful but not self-documenting — new developers needed explicit walkthroughs. I'd invest more upfront in explaining the "why" alongside the "how."