Let’s assume for the sake of this post, that you accept the fact that MVC as a web pattern is well past its due date. What then can replace it? The answer, of course, is VADDR. Don’t worry, it’s not at all related to any Sith Lords you may have heard about.
The primary goals VADDR wants you to achieve are security and testability. Rather than being defined by how the functions and code are arranged, VADDR is defined by the phases that data passes through while processing a web request. Once the phases of data are known, how to arrange the transitions between phases becomes obvious.
These are the 4 data phases in the VADDR pattern:
- VA - Validated/Authenticated Input
- D - Database Records
- D - Domain Objects
- R - Render Objects
Validated/Authenticated Input
That MVC has nothing to say about input validation is reason enough to disregard it as a design pattern relevant to the web.
With VADDR, there is one object per request for Validated and Authenticated Input. Doing the work to create it is the first step in processing a request.
Any URL or POST params and even cookies must be validated first. Upon validation, they are used to create an object that is typed specifically for each request. Subsequent transitions only have access to this object. If it’s all just validated input, it allows the application code and tests to disregard the complexities of the HTTP context.
Also, the validation phase is where the current user’s session and CSRF token should be verified. Any failures to generate this object should cause the app to stop and send a 4xx error. By generating the Validated/Authenticated Input as the first phase of data, each request reminds the developer about the primary goal of security.
Database Records
This bit is most similar to the M in MVC. They are objects that model exactly what lives in the database. The “database” can be an RDBMS, a NoSQL document store or even a local or remote REST endpoint. The point is, this type of object represents what comes from the data source, before any processing or logic is applied to it.
While I/O is necessary to fetch Database Records or write them to persistent storage, transitions between Database Records, Domain Objects and Render Objects should be pure. This helps make the most important parts of the program easily testable, another of a developer’s primary goals.
Domain Objects
In MVC, Database Records, Domain Objects and Render Objects are often merged into a single type. When the single object doesn’t exactly fit it’s application, code complexity ensues. If they are broken up, it’s usually in an ad-hoc fashion that varies from one component to the next even within the same application.
With VADDR, Domain Objects are a distinctly separate idea. Domain Objects represent the domain model of the application regardless of how things are normalized and structured in the database. For example, a Domain Object may aggregate some data from a parent record into a child record as a single object.
Render Objects
The final phase is for passing data to templates, json or other output code. These objects should model the display layout to make front end rendering faster and less complex.
One example might be a HeaderRenderObject. It includes the user’s real name, counts of new messages and any other relevant info meant to be displayed in the header. User info not displayed in the header is excluded from this object as it’s targeted specifically for this case.
In some cases of VADDR, especially for small and/or new apps, there may be no differences between a database record, a domain object and a render object. In this case, there is simply no transformation necessary, but it’s still useful to think about there being 3 applications for that one object. If and when the domain or display start to drift, VADDR expects a new type to be created for the necessary phase, so that the data stays tuned specifically for its purpose. The key to simple code is appropriately structured data.
VADDR: A New Hope
As a pattern, VADDR aims to provide specific guidance on how to phase data so that programs are easier to write securely and maintain with testing. And once the data is phased, designs for simple, testable transformation functions should readily revealed themselves. If this sounds good, give it a try. If not, how would you lay out the phases of data? Write it up, or even better, code it up and post what you come up with.
