Answer To ‘How Would You Design This Adapter? (Part 2)’

This article represents my answer to a system design programming problem

To quickly recap the salient points:

  • AbcPaymentGateway, a wrapper class for calling the API of a payment gateway of hypothetical ABC Corp, uses basic username/password authentication. 
  • As part of the business logic workflow, a call to the datastore is made to retrieve the appropriate payment gateway credentials. These are stored in the Credentials class which has string fields for Username and Password. Credentials does not have a field for AccessToken.
  • We are to write an adapter for the hypothetical XYZ payment gateway too. Luckily, XYZ’s API also uses basic username/password authentication. Unfortunately, it also requires an additional, rarely changing access token. 
  • The question was along the lines of how can we implement XyzPaymentGateway and need to make the fewest number of changes to our existing system?

Well, one approach we could take is to add AccessToken to the Credentials class:

  public class Credentials
  {
     public string Username { get; }
     public string Password { get; }
     public string AccessToken { get; }

     public Credentials(string username, string password, string accessToken)
     {
        Username = username;
        Password = password;
        AccessToken = accessToken;
     }
  }

If we are currently storing the Username and (encrypted!) Password in separate columns in our database, we would be likely to add another column for AccessToken. We would only put a value in this column when the payment gateway is XYZ; otherwise, the value would be null/empty.

So, the database would change. Data access code would change too – it would need to become aware of this new column. The high-level workflow class, PayForShoppingCartUseCase could remain oblivious to such detail – no change needed here. However, adapter class XyzPaymentGateway must know about the presence of AccessToken since it initiates the calls to the XYZ API. 

Using the approach of adding AccessToken into the Credentials class means that we must make changes in many places. 

Is there a better way whereby we could make fewer modifications to our system?

I think there is. 

In my opinion, conceptually, the AccessToken is a bit like a password. Therefore, the XyzPaymentGateway could combine and un-combine the Password and AccessToken as required and store those as the Password in the database and also in our Credentials object.

For example, if both password and access token were GUIDs then we could simply combine the two and delimit them with a pipe (|) character:

   A6766E0C-0741-46C1-9810-B460A8595759 | FFA194A2-77CF-4435-A673-1C107F6F4FC8

It would be dependent on the password and access token not having pipe characters in them, but it would work. Or as an alternative, we could serialise them into a JSON string and save that in the datastore: 

  {
     "Password": "big fat secure password",
     "AccessToken": "jPAdwv3/jHGC3{A6AY25WKsj3Muv:2FZ~6wjRsVx9;7Z84D5.gtABc74T3k"
  }

As soon as we have an encoding that the XyzPaymentGateway knows about, it can also undo this encoding of the Password and AccessToken from Credential.Password. Let’s assume the encoding is a single pipe (|) character between Password and AccessToken strings. The following function will extract the Password and AccessToken parts:

  private string[] ParseIntoPasswordAndAccessToken(string password)
  {
     return password.Split('|');
  }

I think that could work. The database would not need to be changed, except for possibly enlarging the (encrypted!) Password column size. The Credentials class would not need to be changed. The data access would not need to be changed. The use case code would not need to be changed. The only module that would require changing would be the XyzPaymentGateway adapter – it would need to decompose the Credentials.Password into a Password and AccessToken

These changes would be limited to the XyzPaymentGateway adapter class. AbcPaymentGateway only uses Username and Password and therefore would not need this complication.

The critical takeaway is that in this way, we only wrote new code! And yet, we extended the behaviour of the system to be able to use the XYZ Payment Gateway. There is a SOLID Principle for writing code this way: The Open-Closed Principle

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply