00:00:00.480
Hi, my name is Lauren Voswinkel, and I work for LivingSocial. Yes, that is still a company. Today, I'm here to talk about Service Oriented Architecture.
00:00:06.520
You may know the general idea of what a service is, but when I looked for a clear definition, I found that Wikipedia describes it as an unassociated, loosely coupled, self-contained unit of functionality. That’s quite a mouthful for something that should focus on a singular application.
00:00:19.039
Now, what are the benefits of Service Oriented Architecture or pulling out a service from a Rails application? One benefit is that many tasks can be made asynchronous. You can fire a request and forget about it, allowing it to run in the background and later generate a report or send an email without blocking other processes.
00:00:44.600
It is also parallelizable. For instance, if you are retrieving a list of users or other data, you can make multiple requests simultaneously to the same service and receive responses without waiting for each round trip. Additionally, it is loosely coupled, meaning changes in your service won't necessarily break unrelated components of your application. This leads to faster tests because the test suite can be divided into smaller parts that can run individually. When you make a change in a particular area, you only need to run the tests for that service, which can turn a 30-minute test suite into several 5-minute test suites. The loose coupling also makes it easier to extend and change services without fear of negative impacts on unrelated services. Finally, quicker response times yield an increased velocity.
00:01:36.600
I have always heard about these benefits of SOA and wondered how to build a service. I had tried multiple times to extract services from existing applications and often felt like a dog trying to walk in shoes—stumbling and fumbling around without understanding what was going on.
00:02:02.600
At LivingSocial, our team decided we needed a more accurate, up-to-date payment information service to improve our payment and billing processes. This would also provide merchants with timely information. So we decided to develop a new version of the API, allowing us to implement the features we wanted. We decided to 'dog food' our own client, meaning that the payment team would use the same API for their operations, ensuring no functionality existed in our client that wasn't available through the API.
00:02:44.440
Now, let’s discuss how we actually pulled out this service and separated the client from the service. First, while building a service, you need to determine what the service will do. Services should do one thing well, focusing on providing session information, customer billing, or similar functions. They should be focused on a specific task but can have multiple endpoints. For instance, when creating a session service, you should consider endpoints like creating a new session when someone logs in, checking session activity to confirm the person is still logged in, and destroying a session. The controllers should be built with these endpoints in mind, allowing various requests to be made or received. You must also define what options are available in these requests.
00:04:17.520
Consider filters for responses; for example, if you have numerous pieces of information for a customer, you would want to select which information you want to display, such as their home address, social security number, or credit card details. Additionally, you can retrieve multiple objects in a single request, reducing the number of parallel requests needed. At LivingSocial, we used a gem called Active Model Serializers, which is a great way to control the information exposed through a service. Although you can overwrite the to_json method in your model, it can be problematic if additional filters are not well coded, potentially overriding defaults. Active Model Serializers cleanly pulls out available data from the API and makes it easy to use and understand.
00:06:28.400
The next crucial step is to write tests, which serve as a contract to ensure your service fulfills its intended purpose. These tests confirm that the expected information is available. After this, you need to create client models to help users parse the responses from your service. Avoiding raw JSON responses is key; instead, structure your response data to be comprehensible to users. For rapid prototyping, I developed a sort of meta-programming that would process a JSON hash by creating appropriate models and methods for associated values.
00:08:45.680
While this approach was effective for quick iterations, it lacked concrete structure, leading to fragile implementations. Therefore, it's essential to establish clear tests from the client side to confirm that your service continues to provide expected responses. The following step is to build a communication layer, focusing on how your service will interact with clients. There are several gems available, such as HTTParty and Typhus, to help facilitate communication. I recommend using Typhus because it has built-in support for concurrent requests with libcurl, allowing you to queue up multiple requests and handle them simultaneously.
00:10:31.520
Ensure you wrap the gem during use. Many developers encounter challenges when upgrading gem versions, which can lead to significant changes in the API. Wrapping gems means that when the gem internally changes, you will only need to change your internal methods, minimizing widespread changes in your codebase.
00:12:11.960
A helpful bonus step involves combining client models with the communication layer to form a gem, simplifying the experience for clients. Once your gem is created, it’s important to sever direct dependencies by replacing any database calls with calls to the service you have built.
00:13:48.600
This is the part where you will create a separation between the two applications. Be mindful of this gap; it is essential to avoid complications during extraction. During my initial attempts at service extraction, I faced significant issues, including timeout requests due to a Webrick wall, where a request could get queued up and eventually time out.
00:15:49.920
Next, the focus shifts to enhancing the performance of your service. A round trip will always take longer than a database call. Tools such as StackProf are valuable for performance profiling, allowing you to dig into request performance. While initially intimidating due to the amount of data presented, it can be instrumental in identifying performance bottlenecks. By tracking percentage times spent on various calls and their associated costs, you can uncover the slowest parts of your request processing. This allows you to focus your optimization efforts effectively.
00:20:07.240
The final step is to perform the extraction, transitioning the client or service out of your application. Ensure that you extract not only the tables involved but also separate the database to avoid complications. Reorganize your codebase to remove extracted components, building them into a separate repository that includes all tests and functionalities for that particular service. Thank you.