Monday, March 8, 2021

Refactor Everything. Then Refactor Everything Again.

This post has been very difficult to write. In some sense, the process of writing it mirrored what the next step of building out Mabel was really like. I knew that the end result of the post was going to be a description of the final User model that I developed and how it worked. Similarly, I knew that the end result of "the next step in building out Mabel" would result in a concise, unified and rational framework for managing persisted user data. What I didn't know in either case was how to get from start to finish.

With respect to developing the User model, what really helped was being able to generate the following set of requirements that the above mentioned framework must implement:

  1. If I load user data via Redis\User I must do so with the value of the authorization header.
  2. If I load user data via MySQL\User, I want to save the data via Redis\User so it can be used later as the fast source.
  3. However, in some cases I need to perform validation on the data loaded via MySQL\User before I save it via Redis\User.
  4. In some cases I wanted to load data via MySQL\User with the User Name field. 
  5. In some cases I want to load data via MySQL\User with the User Id field.
  6. When I load data via MySQL\User, I want to save the User Id via Redis\Authorization as cases exist where there would be no other way to link the an authorized header value to the actual user account.
  7. When I save data via MySQL\User and am creating a new record, I need to confirm that the User Name, Screen Name and Email Address do not exist for any record currently in the database.
  8. When I save data via MySQL\User and I am updating a new record, I need to confirm that the User Name, Screen Name and Email Address do not exist for any record currently in the database EXCEPT for the record of the current user.
  9. When I save data via MySQL\User, I want to save the data via Redis\User so it can be used later as the fast source.
  10. When I save data via MySQL\User, I want to save the User Id via Redis\Authorization as cases exist where there would be no other way to link an authorized header value to the actual user account.
Once I fully understood what the requirements were, coming up with the implementation was pretty easy. Generally speaking, the code is structured as follows:
  • There are three user models
    • Models\User
    • Models\Redis\User
    • Models\Database\User
  • Models\User requires the other two as constructor parameters.
  • All three models have identical public getters/setters for user data.
  • Models\User has three methods that can be used to load user data:
    • loadFromUserKey
    • loadFromUserName
    • loadFromUserId
  • Models\User has two methods that can be used to save user data:
    • saveToRedis
    • saveToDatabase
  • It's the controller's responsibility to manage which load or save methods to call and in which order. 
  • It's the responsibility of Models\User to manage the transfer of data between itself and Redis\User or Database\User as appropriate.
  • It's the responsibility of Database\User to manage the special validation that occurs when saving user data to the database.
  • It's the responsibility of Database\User and Redis\User to manage the actual communication with their respective services.
It came together pretty neatly in the end and I feel pretty good about it. There's very little duplication of code. I expect it'll be relatively straightforward to unit test and it's not terribly confusing code to read through.

No comments:

Post a Comment