Performance Optimization

Summarized using AI

Nitty Gritty Service Building

Lauren Voswinkel • February 04, 2015 • Earth

In her talk at RubyConf AU 2015, Lauren Voswinkel explores the process of building a Service Oriented Architecture (SOA) by extracting services from existing monolithic applications, particularly focusing on Ruby on Rails.

Voswinkel emphasizes the importance of understanding the nature of services, defined as loosely coupled, self-contained units that offer specific functionalities. She outlines the numerous benefits of adopting SOA, which include:

- Asynchronous Processing: Services can handle tasks in the background, allowing other processes to continue running without delays.

- Parallel Requests: Multiple requests can be made simultaneously, significantly reducing wait times compared to sequential requests.

- Loose Coupling: Changes within a service do not disrupt other components in the application, leading to more manageable code and faster testing.

- Improved Testing Efficiency: Tests can be more focused and run individually, decreasing overall testing time from potentially 30 minutes to just 5 minutes for specific services.

- Increased Development Velocity: Services can enhance response times and optimize workflows.

To illustrate SOA implementation, Voswinkel shares a case study from LivingSocial where her team developed a new API for payment processing. This decision was driven by the need for accurate and timely billing information. Some key steps she discusses include:

- Defining Service Responsibilities: Focus on a specific task for each service, and design appropriate endpoints that will perform the necessary functions.

- Utilizing Active Model Serializers: This gem helps manage the data exposed through a service, preventing potential data overload or confusion.

- Creating Client Models: Essential for parsing service responses, these models allow for structured, user-friendly data handling rather than raw JSON outputs.

- Establishing a Communication Layer: Recommendations on using gems like HTTParty and Typhus are made to facilitate effective communication between clients and services, with an emphasis on wrapping these gems to manage internal API changes seamlessly.

Furthermore, Voswinkel advises on how to completely separate the service from the main application, cautioning against common pitfalls such as database dependencies and timeout issues during extraction.

- Performance Optimization: Tools like StackProf are recommended to profile and improve service performance effectively.

The extraction concludes by carefully transitioning the new service out of the existing application, ensuring all related components are appropriately reorganized into a new repository, inclusive of tests and functionalities.

In summary, Voswinkel's presentation delivers a step-by-step guide on pulling services out of existing applications, emphasizing careful planning, testing, and optimization to maximize the benefits of adopting SOA.

Nitty Gritty Service Building
Lauren Voswinkel • February 04, 2015 • Earth

RubyConf AU 2015: http://www.rubyconf.org.au

You've learned about Service Oriented Architecture. You want to use it. You know the benefits to testing speeds, to team velocity, and page load (why do in sequence what can be done in parallel?). Problem is, you're tearing your hair out trying to figure out how to actually pull those services out of your monorail.

This isn't about the metrics to determine what should be pulled out into a service. This talk isn't even about optimizing the service you pull out. This talk is a step-by-step approach about how to successfully pull a service out of an existing app and optimizing its performance.

RubyConf AU 2015

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.
Explore all talks recorded at RubyConf AU 2015
+13