Domain Driven Design
Developing and Maintaining a Platform With Rails and Lotus

Summarized using AI

Developing and Maintaining a Platform With Rails and Lotus

Simone Carletti • May 24, 2016 • Kansas City, MO

In this talk, Simone Carletti presents the development techniques and methodologies utilized at DNSimple to maintain and enhance their Rails platform, with a focus on incorporating the Hanami framework (formerly known as Lotus) into their new API development. The discussion outlines a journey that began two years prior, aimed at decoupling their REST API from the main Rails application.

Key Points:

- Introduction to DNSimple: Carletti sets the stage by explaining DNSimple's business model and their longstanding API service, which has been integral since 2010.

- Development Approach: Emphasizes maintaining a sustainable codebase through the wrapping of dependencies in custom APIs to manage changes without extensive refactoring—a practice that enhances maintainability and simplifies testing.

- Model Management: Carletti elaborates on their approach to Active Record, advocating for a separation of concerns that restricts direct database calls within models, instead utilizing custom APIs for interactions.

- MVC Plus Architecture: Introduces a modified architecture comprising four layers: controllers, models, commands, and services, which clarifies roles and responsibilities, particularly isolating business logic from HTTP requests.

- Hanami Framework: Carletti highlights Hanami's modularity, allowing selective component utilization that fits their needs. The advantages of using Hanami include enhanced organization of the API and the ability to manage interactions effectively.

- Encouragement of Experimentation: Urges developers to periodically experiment with different frameworks and approaches while engaging with broader programming communities to gain fresh insights.

Concluding Remarks: The presentation emphasizes the importance of continuous learning, exploring new technologies, and finding ways to structure applications in more maintainable manners, enabling future experimentation and adaptability.

Developing and Maintaining a Platform With Rails and Lotus
Simone Carletti • May 24, 2016 • Kansas City, MO

This talk illustrates the development techniques, Ruby patterns and best practices we adopt at DNSimple to develop new features and ensure long-term maintainability of our codebase. It also features how we used Lotus to develop the new API as a standalone Rack app mounted under the Rails router.

Two years ago we started a major redesign of our REST API with the goal to decouple it from our main Rails application and expose all the main features via API. It was not a trivial task, but still feasible due to the guidelines we adopted in the last 6 years to structure our Rails application.

RailsConf 2016

00:00:09.580 Thank you very much for coming, all of you. I know it's the last talk, and actually, it's the first talk after lunch on the last day, so I'm pretty surprised to see so many people here. It's really an amazing opportunity for me to be here because it's RailsConf and I work for a company that was somehow born from one of the Rails conferences. So, it's truly exciting for me to talk today about developing and maintaining a platform with Rails and Hanami.
00:00:35.080 As you can see, the title is slightly different from what was published in the program. By the time I proposed the talk and it was accepted, the framework changed its name. So today, you will see references to Rails and Hanami. Sometimes, I will mention Lotus, but keep in mind that Lotus is now Hanami.
00:01:05.869 Yesterday, I was struggling to find a way to break the ice because I'm normally very nervous when I'm on stage. So, I was talking to my co-workers about what to do, and they suggested throwing candies. I said, 'I can't throw candies on stage!' But they insisted, so I thought I would start the talk by engaging all of you to catch some candies.
00:01:17.960 Hopefully, I will not hit anyone! Here we go! You can catch some of the candies. Remember to stay focused; your goal is to catch the candy I throw. It will be worth it, so let's have some fun!
00:02:20.450 My name is Simone, and I work for DNSimple. My nickname is pretty much everywhere, like on GitHub and Twitter. DNSimple is a company that provides domain name registration, DNS hosting, and SSL certificates. You may not have heard about us, but you likely have heard of some of our amazing customers. For example, we provide services to RubyGems, which is integral for many developers.
00:02:48.030 Before I dive into the core of my talk, I have a very important public service announcement: it is not my birthday today! While I know 99% of you won't get that joke, at least two people here will, so you can ask them for an explanation later. It was essential for my safety to clarify that.
00:03:16.519 Today, I want to tell you a story about a feature we've been working on for at least a couple of years at DNSimple. I will share the decisions we made during the development of this feature and some behind-the-scenes insights that facilitated our decision-making.
00:03:36.329 The story revolves around our new API, API version 2. This talk isn't going to be just about building APIs with Rails or any other framework. If you came here with the hope of not hearing about API building, that's fine, but I must share some experiences and insights relevant to API development.
00:04:06.659 We have been providing our API at DNSimple since the very beginning, around 2010. It has always been a core component of our services, with customers using it for various purposes, such as registering domains or provisioning new DNS records, for instance, via Chef, or purchasing SSL certificates.
00:04:36.840 Back in 2013 and 2014, the way people interacted with our infrastructure was quite traditional. We had the DNSimple application, which offered a normal set of traditional APIs. However, we wanted to provide something different, shifting the focus towards an idea of a platform—a toolkit for building things around DNSimple.
00:05:09.780 In 2014, we began to re-engineer our API. As of today, we still maintain our standard API and application, but we've also started offering webhooks and official clients in different languages. The interesting part is that, besides those official clients, everything else you see has been designed and built with care.
00:05:42.750 So, with that background, the first message I want to share today is about the DNSimple approach to Rails. I will introduce the Hanami framework, which we used to build part of our new API. Finally, I want to show you how you can use Hanami or any other framework to interact with Rails.
00:06:15.580 Let's get started with the first part of the presentation—the DNSimple approach to Rails. Our approach is somewhat different from traditional Rails applications. The reason is that we have a fairly large application, and it's common for growing applications to have diverse needs, such as interacting with external services.
00:06:51.240 If your application starts to grow, you might face similar challenges that we did. One of our key principles is to maintain a codebase that’s sustainable over time. Having been in business for six years, we aim to ensure our code remains maintainable for many more years to come.
00:07:38.170 To achieve this, we use a practice where every dependency in DNSimple is wrapped behind a custom API. For example, we have a dependency on a library called Phony that performs phone number validation and normalization. Instead of calling Phony directly throughout the code, we wrapped it in a custom module, the DNSimple Phone Module.
00:08:38.106 This allows us to manage changes better. For instance, if we need to introduce a whitelist for specific numbers due to Phony not recognizing certain country formats, we can simply introduce that within our module without needing to change every instance in the code that references the library.
00:09:12.760 Some of the advantages of this approach include being able to introduce features or extensions like the whitelist without altering the codebase extensively. We also address incompatibilities at a single point and can replace the underlying library in one location rather than changing every single instance.
00:09:54.270 Testing becomes more straightforward, as this way we don’t need extensive mocking of dependencies. In fact, we have another library dealing with our custom DNS records, which also benefits from this structuring. By using adapters behind the scenes, we can manage how testing interacts with existing components without needing to mock original libraries, granting us considerable flexibility.
00:10:45.760 When it comes to Active Record, we have special guidelines that are important for maintaining control of our models. For example, methods such as `find` or `where` cannot be called outside the model itself; instead, we expose a custom API through finders. This means interaction with the data should happen through finders rather than directly utilizing Active Record methods.
00:11:42.690 This separation of concerns allows us to maintain the integrity and modularity of our application. For instance, we might want to create a custom finder to handle special queries without affecting the default behavior of Active Record. This modular approach fosters an organization that can evolve over time without becoming encumbered or hard to maintain.
00:12:21.020 Our models contain no business logic; they merely serve as storage engines. We ensure that every operation that needs business logic or any interaction with external services occurs through services. This keeps our model layer clean and our application maintainable.
00:12:55.960 The guidelines we follow are based on years of experience and are not set in stone. They are continuously evolving based on our team’s learnings. I want to take a moment to thank my team members at DNSimple for their contributions to these guidelines and the quality of our project.
00:13:47.290 Next, I want to talk about what I call the MVC Plus approach that we have at DNSimple. Traditionally, an application consists of two layers—models and controllers. In our case, we essentially have four layers: controllers, models, commands, and services.
00:14:26.100 The controller layer manages incoming HTTP requests, validates input, and parses parameters. Yet importantly, the controller contains no business logic. Instead, we maintain clarity and separation of concerns by delegating business logic to the command layer.
00:14:58.100 Commands encapsulate user business logic within the application. They handle specific operations that a user can perform and may delegate tasks further down to the service layer, reinforcing that no controller directly calls another controller nor do commands interact with each other.
00:15:34.490 On successful execution of a command, we perform operations such as notifying users or logging activities, instead of embedding such logic within the models, helping us avoid complexities that can hinder testing and maintenance.
00:16:06.460 Services are central to our business logic. They contain public methods representing single units of operations that can occur within our application. Each method serves as a functional API call, and services are designed to be stateless to maximize readability and efficiency.
00:16:47.960 We employ dependency injection for creating services, allowing for isolation during testing. With a clear structure established, the services can easily interact with different components across our application while ensuring they maintain state neutrality.
00:17:23.690 However, since we utilize Active Record for our models, we ensure that they act as storage abstractions, solely responsible for persisting data within the database. This allows us to keep business logic confined to the service and command layers.
00:18:12.210 The multiple layers help in codifying our business logic independently of the context of an HTTP request, giving us a neat separation of business logic from framework dependencies.
00:19:14.880 Having structured our application in such a manner allows us to experiment with different frameworks or controllers without a major overhaul. For example, we can introduce Hanami or similar frameworks, maintain similar interactions, and do not need to refactor extensively.
00:20:05.580 After detailing MVC Plus, I want to talk about Hanami. Previously known as Lotus, Hanami is an emerging Ruby framework designed for building modern web applications. It encourages good development patterns and supports modular architecture.
00:21:01.520 One significant advantage of Hanami is that it allows developers to utilize only the components they need for their specific applications. At DNSimple, we leveraged its routing and action handling capabilities to build our API effectively.
00:21:47.930 You can establish modular controls and even shared code between different parts of your application, fostering great organization and maintainability. For example, we use Hanami for our API and leverage its flexibility to manage interactions efficiently.
00:22:29.840 The structured approach in Hanami allows us to define our actions as separate classes rather than functions inside a single controller—this makes it easier to manage and understand each action's responsibilities.
00:23:12.050 To summarize, the main lessons I hope you take from this presentation are two-fold. First, embrace experimentation; explore new frameworks and ideas periodically. Second, connect with other communities to broaden your horizons, as this can lead to fruitful insights.
00:24:01.380 Working across various programming languages and seeing how they tackle certain problems benefitted me immensely. This diverse exposure made me a better Ruby developer, as it challenged me to navigate assumptions and paradigms outside my comfort zone.
00:24:56.860 Thank you for being here today! If you have any questions, feel free to reach out or discuss with me in the hallway.
Explore all talks recorded at RailsConf 2016
+106