Oh Wait, I Did Actually Replace a Data Layer!

Author

Brandon Bruno

Published

Software developers love nothing more than a good abstraction. Ever since object-oriented programming became popular, developers have been looking for ways to simplify, encapsulate, and abstract low-level programming constructs into broad, reusable concepts.

No where is this more common than with N-tier architecture, where layers of logic are abstracted to ensure each is easily replaceable should the need arise to switch underlying technologies. For example, here's a classic three-tiered application:

A three-tier application diagram. UI, Services, and Data Access on top of one another.

While this kind of abstraction is acedemically sound, in practice most applications rarely switch out a core technology without a larger application rewrite - which suddenly makes all those abstractions seem cumbersome, as they present additional layers that developers need to parse and understand as they work through a re-implementation.

Replacing My (Simple) Data Layer

I recently ported several of my personal .NET applications from MS SQL Server to a SQLite data storage backend. Each of my applications uses a data access layer to abstract the database away from application logic, so my goal was simple: re-implemented my data store logic without altering any method signatures, thus ensuring I wouldn't have to touch the rest of the application code.

My DataStore class has a simple purpose: provide methods to load data from a database. The methods are straightforward. Some examples:

public User GetUser(int userID) { }

public int AddExpense(Expense expense) { }

public static List<Expense> GetExpensesForUser(int userID) { }

These do exactly what their signatures imply. Because I kept a clean separation of concerns between domain models and view models, I didn't even have to re-implement any objects when re-implementing this data layer. My method signatures were identical before and after the conversion. Keep in mind the difference between domain and view models:

  • Domain: data models that map directly to business logic (and in my case, database tables)
  • View: the exact fields and data necessary to display data on a UI; these can vary significantly from domain models

My goal was to touch neither of my domain or view models, and I generally succeeded in that goal.

Lessons Learned

So I did it: I replaced a core technology in my web apps without much fuss - all thanks to smart, clean abstractions!

Why did this succeed? To be blunt, these are simple apps. Among them are budgeting tools, a recipe management app, and the Refactor blog platform. Easy, light scopes lead to easy, light architectures - and in my case, obvious and clean abstractions.

What didn't go so well? I did have to alter some business logic and data layer method signatures, but those were moreso caused by the change from Entity Framework (MS SQL Server) to the Microsoft.Data.Sqlite provider, which necessitated some slight model changes when I was pulling back multiple data entities at once (in other words, lots of INNER JOINS in my queries).