Upskill tutorial for abstraction

Hud Wahab
4 min readJul 14, 2023

--

Day 14: Protocols. Property. Abstraction

Hi 👋 I am Hud, a postdoc for engineering data science at the AI Manufacturing Center in Laramie, Wyoming. My funding is running out (AaAaaA !), so while I am actively looking for a new job, instead of doing the 205th coding certificate to prove my worthiness — I thought I’d do design challenges and document how I spend my time upskilling so other engineers can do the same.

Nowadays, certificates are everywhere. Documenting small upskill projects that you can later show off is the best way to get recognition as a professional engineer.

This is day 14 of a 30-day design challenge. Follow along and let me know if you get stuck!

TL;DR tasks

Download the provided code for the challenge.

Task 1: Understand the code and its dependencies

  • Review the provided code and understand its structure and functionality.
  • Identify the existing coupling between the WeatherService class and the requests module.

Task 2: Identify the abstraction opportunity

  • Determine where abstraction can be introduced to decouple the WeatherService class from the requests module.
  • Consider creating a separate class or interface that provides a generalized way to make HTTP requests.

Task 3: Create the abstraction layer

  • Create a new class, such as RequestsClient, that encapsulates the functionality of making HTTP requests using the requests module.
  • Define a method, such as get(), in the RequestsClient class that handles the HTTP GET request and returns the response.

Task 4: Refactor the WeatherService class

  • Modify the WeatherService class to depend on the abstraction (RequestsClient) instead of the requests module directly.
  • Inject an instance of the RequestsClient class into the WeatherService class as a dependency.

Task 5: Update the WeatherService code

  • Modify the code within the WeatherService class to use the abstraction (RequestsClient) for making HTTP requests.
  • Replace any references to the requests module with calls to the appropriate methods of the RequestsClient instance.

Task 6: Test the refactored code

  • Verify that the refactored code functions correctly by running it with test cases or sample data.
  • Ensure that the WeatherService class successfully retrieves weather data without any direct dependency on the requests module.

Task 7: Evaluate the benefits of abstraction

  • Consider the advantages of introducing abstraction in terms of reduced coupling and improved maintainability.
  • Assess how the refactored code can easily adapt to changes in the request module or facilitate testing with mock HTTP requests.

Task 8: Document the refactor

  • Add comments or documentation to explain the changes made and the reasons behind them.
  • Describe the abstraction layer and how it separates the WeatherService class from the requests module.
  • Document any additional considerations or modifications made during the refactoring process.

The mess

In the previous challenge we’ve done away with inheritance, problems solved right? What else can we possibly improve? Let’s have a look.

The code is highly coupled to API requests because it directly calls the OpenWeatherMap API to retrieve weather data for a given city. This means that any changes to the API or its response format could potentially break this code and require changes to be made. Additionally, this code is not easily testable as it relies on an external API, which can be slow or unreliable, making it difficult to write unit tests that depend on this code.

Moreover, my DRY ick sense are tingling whenever I see the word client :

The solution: Protocol abstraction

Protocol to the rescue! We’ve seen how to use this before in challenges 3 and 9. The HttpClient protocol abstraction helps keep low coupling by defining a common interface for HTTP clients that can be used by the WeatherApi class. This means that the WeatherApi class does not depend on a specific implementation of an HTTP client, but rather on any class that conforms to the HttpClient protocol.

We can see this below more clearly when compared with and without the abstraction. This allows for greater flexibility and modularity in the code, as different implementations of the HttpClient protocol can be used interchangeably without affecting the WeatherApi class. Additionally, this makes the code more testable, as it allows for easy mocking of the HttpClient protocol during unit tests.

Oh, and for that DRY ick issue we saw above? Just add more properties!

Conclusion

Congratulations! You finished Day 14 from the 30-day design challenge.

If you have reached this far, you know how to:

  • Use protocol to decouple API requests
  • Properties to improve DRY principles

Check out the day 15 challenge!

Also, you can access the full 30-day GitHub repository here.

💡 My goal here is to help engineering data scientists upskill in design. I’d like to hear from you! Was this helpful? Anything I can improve? Connect with me on LinkedIn | Medium

--

--

Hud Wahab

🤖 Senior ML Engineer | Helping machine learning engineers design and productionize ML systems. | Let's connect: https://rb.gy/vb6au