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.