Summarized using AI

The Curse of Service Objects

Ivan Nemytchenko • September 11, 2024 • Sarajevo, Bosnia and Herzegovina • Talk

In the presentation titled "The Curse of Service Objects" delivered by Ivan Nemytchenko at EuRuKo 2024, the speaker critiques the prevalent practice of Service Objects in the Ruby community, arguing that they are not aligned with Object-Oriented Programming (OOP) principles and often complicate code architecture. The talk is structured around four main perspectives: OOP principles, practical analysis from various articles and repositories, the philosophical views of prominent figures in the software architecture domain, and their implications for managing complexity in dynamic systems.

Key Points:

- Definition of Service Objects: Service Objects are commonly perceived as a standard approach to manage complexity in Ruby applications, but Nemytchenko believes they are fundamentally flawed.

- Code Topology Notation: He introduces a humorous yet practical concept called code topology notation, where methods and classes are visualized symbolically to illustrate their interactions and complexity levels. Examples include wrappers around APIs and service objects with varying complexity, demonstrating how they often share the same structure.

- Complexity Management: Through his analysis, he shows how using Service Objects can lead to increased complexity, especially when a single object handles multiple responsibilities across different layers. He suggests this contradicts the Single Responsibility Principle and undermines layered architecture.

- Refactoring Examples: Nemytchenko showcases several examples from GitLab's codebase to illustrate how service objects grow more complex over time. He advocates for extracting responsibilities into more coherent, modular components, such as business rules and mutators, that enhance code clarity and maintainability.

- Philosophical Insights: He contrasts the Service Object pattern with the ideas of Martin Fowler and Eric Evans, emphasizing their notions of distinct service layers versus the muddled implementation of service concepts in practice.

- Conclusions and Recommendations: He warns against blindly following the service object pattern without a clear understanding of its implications. Instead, he recommends focusing on the specific types of work done by code entities, suggesting a shift towards more modular, layered architectures that honor OOP principles.

The core takeaway is to critically evaluate the use of Service Objects in software design and to strive for clearer, more maintainable architectures that adhere to fundamental principles. Nemytchenko encourages open dialogue on this topic, inviting those who disagree with his views to engage with him.

The Curse of Service Objects
Ivan Nemytchenko • Sarajevo, Bosnia and Herzegovina • Talk

Date: September 11, 2024
Published: January 13, 2025
Announced: unknown

Service Objects were a mistake. It has nothing to do with OOP. It has little to do with ideas of Fowler, Evans and Martin. I analyzed a plenty of open repositories, videos and articles, and in this talk I will show all the flaws of this “pattern”, and how it contributes to complexity management.

Service Objects is most widely accepted practice in the Ruby community. Yet, I insist, it is very controversial “pattern”, and in some cases hurtful. In most cases it opposes the idea of Single Responsibility Proinciple, kills the idea of Layered Architecture and makes our code non-modular.

In my talk I will analyze the idea of Service Objects from four different perspec- tives: 1. Idea of OOP 2. Practice (analysis of articles videos about Service Objects) 3. Philosophy (how it matches the ideas of Evans, Fowler and Martin) 4. Its effect on complexity distribution in dynamics (based on code of GitLab and Discourse)

My goal is to shake your beliefs by exposing issues of the “pattern”, show where we took a wrong turn, and show how ideas of Service Layer (Fowler) and Domain Services (Evans) can be implemented in Rails without all the problems of commonly used pattern.

EuRuKo 2024

00:00:07.600 glad to be here glad to be open in the
00:00:09.960 track and
00:00:12.040 uh I'm going to like for the this year I
00:00:16.800 love to talk about service subjects I
00:00:19.560 spent a lot of time thinking about them
00:00:22.560 and uh thinking about how to think about
00:00:25.720 them so I'm going to be sharing some of
00:00:28.000 the some of my learnings
00:00:31.360 uh a little bit about myself I'm on rail
00:00:35.320 since 2006 so it might tell you
00:00:37.399 something about my age I my current role
00:00:40.160 is CTO at cle.com where we help
00:00:42.760 companies manage their assets and
00:00:44.879 licenses and do it in an easy way my
00:00:48.039 passion is complexity organization
00:00:50.199 optimization so that not that I only
00:00:53.039 love to organize complexity I love to do
00:00:56.399 it in an optimal way so and uh my
00:01:00.640 consultancy called rbbr limited we help
00:01:04.199 small to medium startups to grow their
00:01:06.920 codebase uh so that they don't lose
00:01:09.920 scalability over time and my methodology
00:01:13.320 is painless rails uh it's not too
00:01:16.720 popular yet I hope it's one day it's
00:01:19.000 going to get a bit more popular a few
00:01:21.880 links below feel free to visit them to
00:01:26.119 follow me and read more about my stuff
00:01:29.479 and
00:01:31.680 what I want to say is Service uh like
00:01:35.000 service object is a fake concept this is
00:01:38.240 my statement but service objects
00:01:41.360 nowadays they are a the facto standard
00:01:44.920 of uh a standard way to organize
00:01:48.040 complexity in rails
00:01:49.960 applications and still I do think
00:01:53.320 so and this year I give one hour talk
00:01:58.479 about the curse of Serv objects in
00:02:01.600 Poland in brl and
00:02:05.119 uh today I decided to reshape my talk
00:02:08.879 because first of all it's 30 minutes and
00:02:11.400 second thing I decided to focus on one
00:02:14.000 thing the shape of a service object but
00:02:17.560 to talk about the shape of service
00:02:19.120 object we first uh I I first need to
00:02:21.720 tell you about one thing I invented uh
00:02:24.480 several years ago that was mostly a joke
00:02:27.959 a funny thing to do but uh I call it
00:02:32.080 code topology notation and these days I
00:02:34.720 find it more and more useful and as well
00:02:37.599 as in discussions about architecture
00:02:40.159 about software decisions and
00:02:44.040 uh uh also on a day-to-day job as well
00:02:47.400 to kind of model things and try out so
00:02:51.120 the
00:02:51.920 notation the basic idea there is to
00:02:56.239 display uh objects as little dummies
00:03:00.519 and their hands
00:03:03.239 are uh represent
00:03:05.519 methods so kind of in order to invoke a
00:03:09.440 method you shake uh a guy's
00:03:12.879 hand and if if you take a closer look
00:03:16.400 you might realize that fingers actually
00:03:18.480 represent arguments so the more uh
00:03:21.480 arguments the more fingers but they kind
00:03:24.440 of not a normal fingers but Robo fingers
00:03:27.519 like robot tube fingers so they can
00:03:29.480 access arguments from outside and maybe
00:03:32.360 store them for late resarch in some
00:03:35.280 other
00:03:36.159 methods so I hope you're still with me
00:03:40.239 and to return the method there's a hatch
00:03:42.799 on the belly that which opens and you
00:03:44.959 can grab a result there and also private
00:03:49.400 methods my my favorite concept those are
00:03:52.920 kind of internal hands which only the
00:03:55.799 guy himself can shake uh but no one from
00:03:59.280 from out it
00:04:00.799 can and there's more to it but like the
00:04:06.040 the only the the One More Concept we
00:04:08.840 need is a class and a class is a kind of
00:04:11.680 spawning platform with instructions what
00:04:14.680 object to spawn and there's a lever and
00:04:17.359 you pull this
00:04:18.680 lever and you get an object and of
00:04:22.840 course you can get as many objects as
00:04:24.600 you
00:04:25.520 need and uh what is interesting is that
00:04:29.720 that essentially both objects and
00:04:32.039 classes they have the same topology
00:04:34.639 because lever could actually have
00:04:37.039 arguments could actually have fingers
00:04:40.320 and it's the same thing as a hand and
00:04:43.039 the same with a hand it can have no
00:04:45.400 fingers no
00:04:47.360 arguments so and one example of uh
00:04:52.320 application of this topology is that you
00:04:54.800 can first of all you can reflect
00:04:57.840 complexity of your code by simply
00:05:01.320 expressing um by simply drawing those
00:05:03.960 little dummies and their arms and how it
00:05:06.680 looks like and uh here you can see how
00:05:10.360 complexity grew over time uh when code
00:05:14.720 was uh getting more and more complex so
00:05:18.560 this is exactly how are we going to talk
00:05:20.759 about the shape of service objects I did
00:05:24.360 small research recently and um
00:05:30.520 I was looking for how developers um
00:05:34.840 think what they think service objects
00:05:37.680 are what they useful for and how they
00:05:39.800 look and I'm going to quickly show few
00:05:43.080 examples of service objects I I found on
00:05:46.680 internet and um uh on the right you can
00:05:51.520 see their shape in our code topology
00:05:54.600 notation so this guy is simply a wrapper
00:05:58.240 around Twitter API
00:06:00.199 and you see like we have a Constructor
00:06:02.400 with one argument and we have one public
00:06:05.639 method um here we have a Book Creator
00:06:09.120 service object called Book Creator again
00:06:11.120 we have a Constructor with four
00:06:13.639 arguments um public method uh can accept
00:06:17.960 any number of arguments so we have this
00:06:20.440 kind of funnel instead of fingers and we
00:06:23.240 also have one uh private method uh which
00:06:26.560 you can
00:06:27.400 see uh there
00:06:30.680 again like few more
00:06:33.000 examples and you can see they kind
00:06:36.560 of like the
00:06:39.360 code might look a bit strange for some
00:06:41.960 of you like this example for example it
00:06:44.120 does some validation for for some reason
00:06:46.240 it's still a service this one it just
00:06:48.840 does simple calculation in one line and
00:06:51.039 it's still a separate class and a
00:06:53.440 separate object but
00:06:55.879 anyway um so and there are also
00:06:59.960 like this this example is a little bit
00:07:01.520 more complex there are four private
00:07:03.879 methods but if we try at this stage look
00:07:07.080 at adjust this samples of code if we try
00:07:10.440 to derive an idea of service object out
00:07:12.800 of
00:07:13.520 it the definition would be pretty much
00:07:16.080 it they just do
00:07:17.840 stuff and they all looks the same they
00:07:21.240 they share the shape so the shape would
00:07:24.280 be okay there's a
00:07:26.360 Constructor uh it it usually accepts
00:07:29.360 some arguments there's a public method
00:07:31.280 with no arguments and there could be a
00:07:33.919 number of uh private
00:07:38.720 methods and serious guys are doing it
00:07:41.680 too I'm going to show you this
00:07:45.879 uh example of a service object from
00:07:49.280 gitlab from the codebase of gitlab and
00:07:52.440 it is uh the code is around 200 lines of
00:07:56.919 code and
00:08:00.039 I'm going to show you how how it looks
00:08:02.319 in in this notation it looks like
00:08:06.639 this so but what's what's
00:08:10.120 interesting is that at the beginning it
00:08:12.520 actually looked not too scary so I look
00:08:16.639 at the history of of those changes and
00:08:18.560 in the beginning it it looked exactly
00:08:20.919 like we seen
00:08:22.400 in the start of my
00:08:25.720 talk
00:08:27.599 so and
00:08:31.319 yeah it looks like over time if you do s
00:08:34.479 if you do practice service
00:08:36.240 objects if a certain area of your
00:08:40.120 project will be uh will become more
00:08:42.800 complex the complexity will grow
00:08:45.720 Inward and for me it doesn't look like
00:08:48.720 an optimal way to organize
00:08:50.920 complexity and let me show you how I
00:08:54.519 would do it so my
00:08:58.120 methodology I think there are three
00:09:00.240 pillars three main principles like first
00:09:03.079 of
00:09:04.040 all please do practice layered
00:09:07.360 architecture please make sure your
00:09:09.200 obstructions are of a single level of
00:09:12.120 obstruction so that they don't kind of
00:09:14.800 Jump Around multiple layers
00:09:18.079 and around multiple levels of of
00:09:22.079 obstructions and the third one this is
00:09:24.760 the one which we're going to be focusing
00:09:27.079 on I and if if you like if you haven't
00:09:31.920 been listening to me at all and you will
00:09:34.959 remember only one thing after my talk I
00:09:37.240 want you to remember this thing so think
00:09:39.920 about this idea splitting code
00:09:43.120 into uh into different building blocks
00:09:46.399 by the types of work this code is doing
00:09:49.720 and let me show show you what I mean we
00:09:51.880 will take this service object which is
00:09:54.959 not too big like gitlabs which is
00:09:57.320 already not too small and there are
00:10:00.200 like we can already start considering a
00:10:03.320 refactor inovate or at least we can
00:10:05.880 easily demonstrate the idea of types of
00:10:07.959 work here
00:10:11.760 so I'm not sure if you if you can see it
00:10:15.040 but um below like uh what what this code
00:10:20.600 does it calls um it sends an email so it
00:10:24.079 uses some external service and um you
00:10:28.839 can see here I kind of highlight arms of
00:10:33.000 of this guy to represent um where this
00:10:37.920 type of work um is
00:10:40.279 located
00:10:42.600 so here we can see mutations so we do
00:10:46.079 mutate do some changes in the database
00:10:49.279 and this logic is spread across two
00:10:51.480 private
00:10:53.440 methods uh this one is what I call
00:10:56.399 business rule it is where we ask a user
00:11:00.399 about something about not about
00:11:02.279 something about himself I mean user
00:11:05.399 entity and again this logic is spread
00:11:08.279 across two private methods and we can
00:11:10.839 also see that uh service object
00:11:15.279 also works to some extent as a
00:11:18.079 controller at least it has a notion of
00:11:20.320 session it of JWT talking uh it has a
00:11:25.120 notion of rendering at least It prepares
00:11:27.880 success or result and
00:11:30.000 response so yeah we can see that here
00:11:35.360 the guys take care about all those types
00:11:37.959 of works and let's see what's going to
00:11:40.320 happen when we um try to rearrange it so
00:11:45.480 that each type of work is done within
00:11:48.600 its in its own building block let's find
00:11:51.760 its own shelf for every type of work
00:11:53.800 being done here so first of all let's
00:11:58.120 extract
00:11:59.760 business rules and luckily in rails we
00:12:04.040 kind of already have a proper shelf for
00:12:07.000 for business rules if we ask
00:12:09.519 user uh about himself let's maybe just
00:12:12.680 move it to a user
00:12:14.079 model and yeah that's the code that's
00:12:18.760 the shape of our user we just added two
00:12:20.720 methods to a user
00:12:22.839 model okay next
00:12:25.680 step uh mutations
00:12:29.480 and this might be a not not very obvious
00:12:33.680 move um what I do here
00:12:38.880 I I introduce a concept of mutators and
00:12:42.639 those mutators are just functions
00:12:46.800 and I just move all the logic all all
00:12:51.079 the creation logic all the update logic
00:12:53.600 in one single procedure so it's not the
00:12:57.760 logic is is not getting
00:13:00.600 um um split across multiple models in
00:13:05.440 callbox for example it is all in one
00:13:07.639 method it's explicitly uh it is an
00:13:10.279 explicit procedure so
00:13:13.279 and module I use just as a container for
00:13:16.600 those functions I call it user module I
00:13:19.920 call it user mutator but the actual
00:13:22.920 mutators are functions so um yeah we
00:13:27.040 introduce basically two functions here
00:13:30.120 um next move let's extract all the
00:13:33.920 controller Logics back to the controller
00:13:36.800 so that because before that our service
00:13:41.279 object was working as a controller and I
00:13:44.600 assumed that uh controller was just
00:13:47.160 calling this uh service object and it
00:13:49.519 was mostly
00:13:51.079 empty so it was maybe too
00:13:54.360 skinny okay so we just uh moved some
00:13:57.040 logic to controller and we like
00:13:59.880 obviously we already had this had this
00:14:02.079 thing uh we just modified uh the create
00:14:05.639 uh
00:14:08.320 action okay and once we moved everything
00:14:12.079 out let's see what's left in our service
00:14:15.759 and
00:14:16.560 again
00:14:18.920 um again it's just a function or more
00:14:23.399 correct
00:14:24.519 procedure again it is located within a
00:14:27.680 module but it could be class as well
00:14:29.759 because the top topology is the same I'm
00:14:31.720 not creating any objects here it's just
00:14:35.279 a method which accepts three arguments
00:14:38.600 and does its
00:14:39.839 job and you can see that um it calls
00:14:44.560 user it calls some method methods from
00:14:46.959 user model it calls it asks to do some
00:14:50.480 job for user mutators and it calls um uh
00:14:56.120 it involves a method in a user mailer so
00:14:59.360 instead of us having like a big piece of
00:15:02.639 code doing lots of different types of
00:15:05.839 low-level work we now have a
00:15:09.759 highlevel code which uh we fit in a
00:15:13.839 single function so this is what we did
00:15:17.320 essentially this is what we had and this
00:15:20.120 is what we've got so we introduced five
00:15:23.680 methods we modified uh a control
00:15:26.079 diretion uh two methods went to uh to a
00:15:29.319 model and we introduced three me methods
00:15:32.240 and we
00:15:33.319 found
00:15:35.040 uh kind of building blocks for them
00:15:37.720 which
00:15:38.560 are simply containers of uh of
00:15:46.759 functions so here you can see how we uh
00:15:50.480 distributed all the types of work across
00:15:52.959 different building
00:15:54.240 blocks and
00:15:57.160 uh interestingly
00:15:59.839 if we try to uh draw how it's how it's
00:16:04.560 used it looks like uh our user is
00:16:07.920 getting used by user
00:16:09.920 mutator
00:16:11.759 our uh service uses uh mutator and it
00:16:16.600 can use model as well and controller can
00:16:20.120 use uh any of them basically so and it
00:16:23.839 will be very strange in this
00:16:26.000 architecture if you would try to use a
00:16:28.279 service from my mutator it's not what
00:16:30.759 you expect here and
00:16:35.279 basically you can easily spot that if
00:16:37.680 you prefer isolated testing this setup
00:16:40.560 would be much easier to
00:16:42.279 test also this is what we call
00:16:46.120 modularity and this is what we call
00:16:48.079 layered
00:16:49.759 architecture and I want to remind you
00:16:52.920 that
00:16:53.920 rails is supposed to be a layered
00:16:56.800 architecture just that they were just
00:16:58.959 two layers models and controllers and
00:17:01.759 with the idea of service objects we
00:17:03.839 actually what we wanted to do is to
00:17:05.520 actually introduce another layer kind
00:17:07.720 service
00:17:08.679 layer but uh I think as a community we
00:17:12.880 failed and essentially we have no layers
00:17:15.559 anymore and but this is what we've got
00:17:19.360 with mutators and with services this is
00:17:21.839 the architecture what we've got like uh
00:17:24.240 in the core we have our Primitives our
00:17:26.079 entities models then we have mutators
00:17:28.679 who who can operate with our entities
00:17:31.679 there are and then there are more high
00:17:33.440 level obstructions like Services which
00:17:35.960 represent business operations in my code
00:17:39.160 and they are kind of smarter things they
00:17:41.080 can operate with mutators and models and
00:17:43.840 controllers like they uh manipulate all
00:17:46.720 the things below so but one could say
00:17:51.440 wait we could still while refactoring
00:17:54.520 that service object we could still uh
00:17:57.200 put those kind of
00:17:59.400 we could still use service objects for
00:18:01.360 those types of work right and let's do
00:18:05.360 this so this is the code which I put
00:18:08.760 like two methods to a user model uh I
00:18:11.760 extracted let's put them in a separate
00:18:14.120 service object instead of doing this so
00:18:17.039 I create a class called user business
00:18:19.799 rules and there's a Constructor and
00:18:23.080 there are two public methods which
00:18:25.679 actually give us answer about this user
00:18:31.960 um user um user
00:18:37.120 mutator uh we turn it into two service
00:18:40.120 objects with the names login event
00:18:43.320 recorder and failed login
00:18:45.840 Handler and yeah we've got two of these
00:18:49.400 little dummies here and service yeah we
00:18:53.200 we also turn it into a service
00:18:55.280 object and this is what we've got
00:18:59.159 so on the black part this is amount this
00:19:02.880 is how our topology how topology of our
00:19:07.039 code looks like with the idea of with
00:19:09.679 the just idea uh of types of
00:19:13.120 work and with with this idea plus the
00:19:17.360 idea of service objects we get this
00:19:19.240 amount of complexity so we get
00:19:23.600 um I would say we have uh we we get a
00:19:27.039 decent amount of accidental complexity
00:19:29.840 here and this is what I mean this is
00:19:33.640 what I mean by finding an optimal way to
00:19:36.919 organize complexity so on the left this
00:19:40.400 is what we had before refactoring and
00:19:44.159 this is and this we don't like because
00:19:46.559 complexity would grow Inward and we we
00:19:48.799 will get infinite number of private
00:19:51.039 methods uh and on the right this is what
00:19:53.960 I would get if I would be keep using
00:19:56.520 service object even if I don't have to
00:20:01.039 so and this is how it's going to look
00:20:03.919 like uh on a scale so this is
00:20:08.600 how uh some of my shelves for building
00:20:12.640 blocks for different types of work look
00:20:15.440 like so I have Services I have mutators
00:20:18.559 I have managers managers in my code are
00:20:21.280 just wrappers around um external
00:20:24.440 Services I have forms I have business
00:20:26.960 rules they go just as a method to my
00:20:32.880 models and yeah um I get this layered
00:20:38.360 architecture and at this point I would
00:20:41.720 Reen I would like to rename my talk and
00:20:44.640 new name of my talk would be the shape
00:20:47.640 and the missing idea of a service object
00:20:50.760 because at this point I
00:20:53.320 think uh there is
00:20:56.240 no idea there is no philosophy ophy um
00:21:00.640 um in service object I think the only
00:21:03.840 idea of a service object is its
00:21:07.120 shape and what
00:21:09.840 I very much dislike about this is that
00:21:13.559 it makes you focus on a wrong thing it
00:21:17.240 makes you focus on an empty concept
00:21:20.120 instead of really organizing your code
00:21:23.080 you're just focus on the
00:21:26.279 shape and this is what we get
00:21:29.240 so we just
00:21:30.679 get a very very different um service
00:21:35.440 object which either uh do different
00:21:39.320 types of work and they are put into the
00:21:42.679 same bucket or
00:21:46.000 Worse um inside service object they do
00:21:49.480 all the different types of work and they
00:21:51.720 still put in the same bucket and this
00:21:54.919 bucket like is located um
00:21:59.120 it's it's located nowhere and
00:22:02.640 everywhere because um it it
00:22:08.360 steals all the responsibilities from
00:22:10.720 controllers layers and all the
00:22:12.720 responsibilities from the model layer
00:22:14.480 and it it it does everything basically
00:22:17.320 so with this idea we effectively kill uh
00:22:22.200 uh lay
00:22:24.039 architecture and one more
00:22:27.200 thing I want want to
00:22:30.520 share like not only I did some research
00:22:33.520 about um about how developers do service
00:22:37.240 object I also tried to find how like
00:22:41.400 smart people who were thinking about it
00:22:43.760 like years before in this example fer
00:22:46.960 and Evans what they were saying about
00:22:50.159 service objects and surprisingly they
00:22:53.120 didn't say a thing so but what they said
00:22:56.520 about fer mentioned mentioned an idea of
00:23:00.240 service layer and Evans mentioned domain
00:23:03.640 services and I'm not going to
00:23:06.799 um share the whole
00:23:09.159 story but what I did basically I um
00:23:13.159 represented visually what they were
00:23:15.520 saying
00:23:17.320 and this you will be able to see in
00:23:20.400 details in my presentation which I going
00:23:22.640 to share in the end of my
00:23:24.640 talk and Evans ideas they look
00:23:28.960 like this what I wanted to share here is
00:23:32.600 that I took their
00:23:35.520 ideas and I kind of decided to make it
00:23:38.880 more compact I assume they were talking
00:23:41.799 about the same idea because it looks
00:23:44.159 like it and I kind of compressed they
00:23:47.520 what they were saying
00:23:49.480 about and this is what they were saying
00:23:52.279 about so they're saying that domain
00:23:56.159 service is stateless it is named for an
00:23:59.279 activity not entity it represents
00:24:01.279 business operation so some calculation
00:24:04.679 not some random calculation is not a
00:24:07.720 business operation a rapper around uh
00:24:11.240 rest API is not a business
00:24:13.400 operation it coordinates the main
00:24:15.640 objects it controls
00:24:17.799 transactions uh it should theoretically
00:24:20.039 have side effects it could happen that
00:24:22.559 there will be no side effect because
00:24:24.240 some some if condition but theoretically
00:24:27.840 there like it there should be a side
00:24:29.760 effect and there should be no
00:24:31.159 application logic because Evans
00:24:33.840 specifically he draws a line between
00:24:36.600 domain services and Technical Services
00:24:38.960 and he says those are not the same those
00:24:41.000 are different things
00:24:43.279 so and what we what we've got here is
00:24:47.200 that we actually crafted a ruler here
00:24:50.679 and we can take every service around we
00:24:54.000 can uh grab any service object and we
00:24:57.159 can measure with this follow Evans ruler
00:25:00.600 and see like uh to what extent it
00:25:04.760 matches what they were
00:25:06.399 saying
00:25:09.080 and the good news is that I actually um
00:25:13.640 I made a custom chart
00:25:15.279 GPT where you can put your code and it
00:25:19.200 will tell you how much uh how many
00:25:21.799 points it gets according to this ruler
00:25:25.679 and if you get five out of s most
00:25:29.880 probably you're using service service
00:25:32.760 object where you don't have two where
00:25:35.240 function will be enough I recommend you
00:25:38.120 to play with it uh it's going it is fun
00:25:42.360 and my general
00:25:46.000 recommendations don't use the term
00:25:48.039 service object because again it's an
00:25:50.200 empty concept it's an empty abstraction
00:25:52.559 there is no deep philosophical idea
00:25:55.840 behind it uh second recommendation don't
00:25:59.360 use service
00:26:01.200 objects um you still can but you if you
00:26:05.679 do you should be ready to answer the
00:26:08.320 question what is your personal idea
00:26:10.760 behind it so you can still use it as a
00:26:14.840 like as a technical trick if you find it
00:26:17.320 useful I don't find it useful I find it
00:26:21.760 confusing um and types of work of your
00:26:26.559 your code is doing is essentially type
00:26:28.399 of building block you have in your
00:26:30.720 applications and um and yeah do try to
00:26:34.679 measure your services with fer evance
00:26:37.240 ruler
00:26:39.000 and the good news is that all this stuff
00:26:43.320 uh is pretty easy to find just go to
00:26:46.120 rails. Services there I put my uh
00:26:49.880 presentation there I put uh some links
00:26:53.320 from the talk there I put the link for
00:26:55.919 this fer evance ruler and and there you
00:26:58.799 can find the recording of my talk in
00:27:00.640 Poland one hour long where I was talking
00:27:03.559 about all this in much more details
00:27:06.960 thank
00:27:17.720 you and one thing I do uh if you
00:27:22.760 disagree with me please find me and talk
00:27:26.320 to me I would love to for you to explain
00:27:28.679 me why service objects is a good idea
00:27:31.120 maybe I'm still missing something I
00:27:33.399 would love you to to tell me that thank
00:27:35.559 you
Explore all talks recorded at EuRuKo 2024
+39