this post was submitted on 24 Jun 2023
8 points (83.3% liked)

Experienced Devs

3978 readers
1 users here now

A community for discussion amongst professional software developers.

Posts should be relevant to those well into their careers.

For those looking to break into the industry, are hustling for their first job, or have just started their career and are looking for advice, check out:

founded 1 year ago
MODERATORS
 

Hi everyone,

In a project involving Firebase and object types like Tickets, Schedules, and Timers, I want to structure my classes such that switching databases (potentially to MySQL) wouldn't require a complete rewrite.

Approach 1:

  • A DatabaseProxy interface with generic methods (e.g., createTicket, createTimer, etc.)
  • A FirebaseProxy class implementing the interface, with methods for each object type (e.g., createTicket, createTimer, etc.)
  • Manager classes for Tickets, Schedules, and Timers, that primarily use the FirebaseProxy for operations. This provides flexibility for processing input/output, but most of the time the manager classes will just be calling methods on the Proxy directly.

Approach 2:

  • A DatabaseProxy interface with the most basic CRUD methods (create, read, update, delete).
  • A FirebaseProxy class implementing the interface.
  • Manager classes for Tickets, Schedules, and Timers, calling FirebaseProxy with parameters like update(collection, ticket) and implementing createTimer, createTicket, etc.

I like the second approach in theory, but what I'm worried about is whether the separation is too low level. What happens if the database I switch to changes schema such that taking in an object and a collection name isn't good enough anymore? For example, will there be concerns if I switch between Vector, NoSQL, and SQL?

Any opinions are appreciated!

top 3 comments
sorted by: hot top controversial new old
[–] [email protected] 4 points 1 year ago* (last edited 1 year ago)

Hello. Appreciate your question. I think that this is a good use case for the Repository Pattern.

Image describing the Repository Pattern

In your case, this might look something like this:

  • TicketRepository, ScheduleRepository and TimerRepository interfaces which have their functions like create(), read(), update(), delete(), complexQueryByManyParams() etc. All your domain code should expect and operate on these interfaces.
  • FirebaseTicketStore, FirebaseScheduleStore, FirebaseTimerStore classes which implement the respective interfaces. All your logic that relates to Firebase should be encapsulated here.
  • You can later safely do things like swap out a FirebaseTicketStore with a MysqlTicketStore

You can consult the Design Patterns / Gang of Four book for more details

Off topic, but personally I don't feel you should worry too much about having to change the database in the future. I have rarely seen it happen in my career.

[–] [email protected] 1 points 1 year ago

I would generally say to stick to approach 1, as much as that stinks. Your observation about approach 2 especially compounds once you start to look at more complex operations that need to be optimized based on how the underlying DB works. Care still needs to be taken in approach 1 to avoid non-optimal operations, but at least you have the freedom to rework individual methods on your DatabaseProxy instead of all FirebaseProxy methods using your underlying CRUD operations.

One of the fastest ways I get people thinking about this is asking

How would you implement a listTimers or listTickets API with cursors?

Generally that's complex enough to bring out pain points.

[–] [email protected] 1 points 1 year ago

Look into "Hexagonal Architecture", similar/synonymous to clean/ports&adapters/onion. As someone else said, combine it with "Repository" pattern.

I use hex arch in front end and back end. It adds a couple of layers, but it makes apps much easier to test and maintain.

load more comments
view more: next ›