00:00:20.560
Hello everyone, if you would like some help creating a standalone service or if you have ideas about architecting your system to allow you to build these independent services, that's what I'm here for. My name is Mando Escamilla, and I work for a company called Union Metrics. Union Metrics provides social media analytics; we gather a lot of data from various social networks, including Twitter and Tumblr, and conduct deep dives on that data for our customers.
00:00:35.120
The best way we have found to architect this large system is to apply micro philosophies in building your software to the entire system at large. Solid principles, like the Single Responsibility Principle, are important and should not just apply to writing your code; they also apply to architecting your big system. By adopting a service-oriented approach, we can more easily apply those principles. The first step in implementing this is to identify areas in your application where creating a service would be beneficial.
00:01:23.040
Look for places that provide reusable data or actions. If different areas of your application are seeking data from one place or if you have a function that works well and multiple places need it done, it's a good candidate for a service. Anything that provides data, generates reports, or consumes and creates information can also be a good candidate for a service rather than being set up in a monolithic application.
00:02:11.799
Once you identify a candidate for a service, the next step we take at Union is to write a specification. These specs are detailed and serve as a solid foundation for your project. I've been involved in many development environments, some of which had very top-down designs, creating documents that outlined everything in great detail before a single line of code was written. Conversely, I have also worked with teams that were very agile, avoiding strict guidelines. However, when writing services, we found that you can't overthink the problem; spending time on a solid spec is crucial.
00:02:55.920
In a recent example, we built a service called Spectator, which gathers various bits of information about entities on social networks, like observing a Twitter account. The shape of the spec for this service is defined from its URI to the request body and parameters that are required for the service to function. This includes optional authentication credentials, as some services require it while others do not. Having a solid contract, like this spec, makes it easy to write both the client and server.
00:04:34.560
We start by writing the client first because it forces us to focus on error handling before the service is operational. It's essential to ensure that we handle situations where the service might not exist or is providing bad data. This approach helped us put in error handling before the complete functionality was finished. When Spectator goes down, instead of breaking the page or showing an error message, we return an empty graph with a friendly message, ensuring user experience remains intact. This error handling design was crucial for our production environment.
00:05:35.360
Next, we move to defining a basic connection configuration, which involves setting up a YAML file for configurations that resembles the database.yml file. We use a concise client sketch that loads this configuration to simplify our HTTP clients' access to services. Having a unified way for all HTTP clients to communicate is incredibly important; it prevents confusion that can arise from different error handling patterns and styles across services.
00:08:01.440
The client handles sending requests using HTTParty, which simplifies our operations. We manage responses based on the HTTP codes and have a specific error exception to provide detailed information in the event of an issue. Once we set up the unified access, we write the client itself, ensuring it can handle interactions with the service effectively. The goal is to keep the client's functionality simple by providing clear and necessary methods while ensuring all requests and handle credentialing properly.
00:09:51.960
Testing for Spectator was approached without strictly adhering to test-driven development. Since the client was still being defined, we had to sketch it out without formal tests initially and add those once we understood its behavior better. Testing tools make this process less painful by helping us mock expected requests and behaviors without relying heavily on external systems. This allows clear vision into the service's expectations, aligning with our previously defined specs.
00:10:54.000
To ensure we have a working service and a functioning client, we need to integrate them carefully. This part often requires significant effort, and although there isn't always a foolproof method, making sure both components communicate correctly is essential. We implemented shortcuts that allow clients to return local data without needing to rely on live services for everything, aiding both development speed and testing processes.
00:12:58.000
After setting up and testing the service, we also need to handle operations effectively. Operations teams are often burdened when new services are introduced because this adds more tasks to manage. While developing more services can be necessary, we must balance this growth with operational capabilities. Additionally, developers need to be aware of the risks involved in multiple service architectures, including dependencies on different operational contexts.
00:15:18.800
Despite challenges, adopting a service-oriented structure has substantial rewards such as simplified deployments and the ability to build and ship smaller, independent components without disrupting the entire system. It encourages experimentation and agility among development teams as services can be built and maintained more independently using diverse technologies as needed, enhancing developer satisfaction. Managing dependencies properly and making sure teams are regrouping efficiently ensures that the agility of service-oriented architectures can be sustained.
00:18:01.200
In conclusion, while there are various rewards, including developer happiness and experimental freedom, it's crucial to remain mindful of potential risks, such as operations overhead and maintaining context across multiple services. If you’re interested in working in a dynamic environment centered around service design and analytics like I have at Union Metrics, I would love to chat with you more about it after this talk. Thank you, everyone!