Skip to content

Instantly share code, notes, and snippets.

@hopeseekr
Created June 13, 2019 07:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hopeseekr/d4d7902af000f709bcc6fc98b6ab1cae to your computer and use it in GitHub Desktop.
Save hopeseekr/d4d7902af000f709bcc6fc98b6ab1cae to your computer and use it in GitHub Desktop.
DTOs in Action: The ColorSpeaker Project

ColorSpeaker was inspired by the article Tests and types [mirror] that was posted to /r/PHP two days ago.

Its aim is to be an easy-to-use converter for different types of color models (RGB, CSS hex codes, HSV, HSL, etc.). It is also meant to be a real-world example of the power of Data Transfer Objects (DTOs). I specifically created this for one of my apprentices whom I taught DTOs to the night before I read the above article, and thought this would be a perfect project for showcasing DTOs.

I developed it in three distinct iterations:

  1. [v0.25 tag]: A virtually literal implementation of the article's one color DTO (RGBSpeaker and RGBColor). This is a great place to start learning about DTOs and is meant to be used in conjunction with the article that inspired it.
  2. [v0.50]: I then added the CSSHexSpeaker class and properly moved all hex code functionality to it. But I didn't like the end-user experience (needing to use two different classes just depending on the type of color inputed).
  3. [master]: In the third teration, I went full Composition (vs. Inheritance) [m] and Design by Contract [m] and ended up with a single public class: ColorSpeaker.

tl;dr: Now you can easily load one type of color and transliterate it into another color model, effortlessly:

$hexSpeaker = ColorSpeaker::fromHexCode('#7b6F37');
$rgbColor = $hexSpeaker->toRGB();

    $csvHex = "color: $hexSpeaker;"; // color: #7B6F37;
    $csvRGB = "color: $rgbColor;";   // color: rgb(123, 111, 55);

This is all made possible by my SimpleDTO Project.


Want to learn even more? Check out the really complex DTO usage in my Zuora API Client. Zuora's API is not good, in the sense that their GET and POST and even PUT requests/responses do not line up with the same property names and even differ in being CamelCased or pascalCased.

Plus, their documentation is very difficult to read, in that you have to just "know" to click the > 200 OK to see the response payloads, and what's worse, they are many levels of nested objects. To create a customer subscription, for instance, requires 6 levels-deep of nested objects.

Now, you can spend hours each day pouring back and forth between the Zuora docs and your code, like I used to, or you can write the DTOs once, and then just start typing -> and you can quickly see via your IDE all of the possible properties, and which ones are required and not (nullable). See my test for creating Zuora Customer Accounts to see how easy complex DTOs are in practice.

Plus, isn't looking at this a lot easier than trying to grok their documents on what, exactly, is needed to create an Account?

Update: My friend suggested that I also showcase my NeverBounce API Client for a much simpler example of how to use DTOs to interface with APIs, which was what Martin Fowler originally invented them for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment