00:00:08.179
Thank you everyone for having me back. I had a blast last time, staying about five days in the beautiful city of Lviv. I enjoyed discovering all it has to offer and I'm thrilled to see that you have an amazing community here. When I was here, I visited your free Rails course and I would love to know how many of you are alumni of that course. I know at least one person here was, who I recognized from the last time I was in town. I'm very happy to be back, and I'm excited to meet all of you. It's great to reconnect, especially with familiar faces like Anton, who has since moved to Kyiv.
00:01:10.030
In such a great community, one important thing you need is to organize events. So today, let’s build an app to help organize an event. An event typically has a name, a location, a date, and a schedule for the crew and performers. It also has a start and end time, among other details. However, repeating the date appears cumbersome, especially if it’s a one-day event. Instead, we should have a single date entry and simply reference the times. This approach is a perfect opportunity to create our new MVP for event management software.
00:01:42.290
To make this application work, we could implement a before validation hook. This feature will handle the time fields to set dates correctly by leveraging Ruby’s powerful capabilities. By entering the event date, the hook can automatically adjust the time fields. We can then check whether the event setup works correctly, indicating that our new event management software is effective. However, this simplicity can lead us to overlook potential pitfalls; for instance, if we save an event with an arbitrary date in the future, there may be unexpected consequences due to this hook.
00:02:56.269
When performing tests on a future date, we might find that values revert to a default state due to our validation hook. This unexpected backtracking to a previous date can cause significant confusion, leading to failed tests because the event is technically considered valid as it references an outdated date. As developers, this can lead us down a rabbit hole of debugging and might lead us to wrongly conclude that our query implementations are flawed instead of recognizing the issue in our event setup.
00:03:59.990
This situation leads me to believe that before validation hooks can be a sign of trouble. Such hooks can subtend problems by obscurely changing inputs—their presence can suggest that something might not be right. Validations can often go awry when they become overly complex and tied into business logic, leading to maintainability issues. For instance, a model's responsibility is not to sanitize all inputs before each validation run. This approach can lead to unusual side effects, like CPU-bound execution times, along with silent errors when validations get skipped altogether.
00:05:35.269
As we explore the concept of validations, let’s look at an example from a user model in GitLab. Good engineers, even those at large organizations, can still produce code that isn’t entirely straightforward. In this instance, we see complex conditional validations for unique emails that can cascade from various situations, reflecting a defensive coding approach—where one validation can easily obstruct another. The design leads to complicated logic flows that can be hard to debug.
00:06:31.159
Taking a step back, we need to ask ourselves why such convoluted patterns persist. Could it be that we’re not considering the affordances of our code? Affordances relate to how a piece of software is intended to function: for example, when designing forms, how are we communicating requirements to the user? By simplifying how we handle code segments and validations, we can make sure our software stays maintainable.
00:06:56.270
Validations can eventually lead us to overcomplicate our models. When we include too many responsibilities in our user models that relate to things like email formats or terms of service acceptance checks, validations may inadvertently end up cluttering our code. Most validations should reflect specific business logic and not become a catch-all for every possible state.
00:07:55.920
In many cases, the same value being validated against multiple attributes can result in tangled, overlapping concerns. This makes it very hard to track down issues that arise during development. If multiple states trigger side effects, we risk entering into complex debugging scenarios—inevitably making it more difficult to understand what the intent was behind each validation rule.
00:08:37.850
Next, as we consider alternatives to handling validations in our Rails applications, we might focus on implementing service objects or form objects, both of which can help decouple validations from models to manage duties effectively. This way, validation logic can reside within dedicated classes that only serve to validate specific scenarios without needing to interfere with each other or the database layer.
00:09:40.580
For example, using a form object would separate the registration flow of a user: handling inputs for creating a user, such as emails and passwords, can reside in a dedicated object that knows nothing about the database or persistent conditions. Hence, it only focuses on simply ensuring the correct format, information, and handling any operations, including sending welcome emails in a direct method.
00:10:54.950
Thus far, we have covered potential issues, such as excessive validations and unintended coupling due to complex dependencies across models. Now, let’s say we transition more towards utilizing service objects to handle particular tasks while isolating unnecessary validations and callbacks, making overall structural designs clearer and easier to manage.
00:12:02.500
I will also bring attention to libraries that can appropriately achieve this design separation. Services like Active Type, for example, allow you to create separate models specific to a certain context. This means we’re not enforcing irrelevant fields and functionalities in our central user model; instead, we can encapsulate specific logic and validations relevant only to specific features of our application.
00:13:23.750
Finally, let’s distinguish between validations and the various contexts for operations within our application architecture. When using systems like Trailblazer or Hanami, information can flow into distinct parts of an app cleanly, allowing for better readability and, by extension, better maintenance. These frameworks remind us to retain only crucial logic in models while extracting any side functionalities into clearer structures.
00:14:37.940
So, with all that said, what can we take away from my observations today? First off, I don’t harbor any dislike towards Rails; it has shaped many of our careers, including mine. However, it’s important we recognize areas for improvement in how we impose validations and the coupling that occurs when business logic is intertwined carelessly. We should all also consider the affordances of our implementations: does the design properly reflect the purpose and utility of the software—the overall behaviors expected from users and their interactions with it?
00:15:32.800
Remember, in the framework of Rails, there’s always room for us to innovate by ensuring our software designs promote value clarity, making it easier to test, maintain, and extend. Acknowledging the importance of structure and thoughtful separation of concerns can strengthen our future projects—as well as refining how we conceive business logic in a coherent manner that’s more efficient, maintainable, and scalable.
00:16:31.000
Thank you for your attention, it’s been great engaging with all of you on this topic. I look forward to your questions!
00:17:07.600
Thank you! It’s been an insightful session altogether.
00:17:12.300
I appreciate the interaction and perspective shared during this workshop. I’m happy to connect with everyone as we explore how these approaches adapt to our evolution as developers.