<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonathan Steel</title>
    <description>The latest articles on DEV Community by Jonathan Steel (@jsteel).</description>
    <link>https://dev.to/jsteel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F721366%2Fc1d9422a-203d-4d89-b8f3-0adc29165945.jpeg</url>
      <title>DEV Community: Jonathan Steel</title>
      <link>https://dev.to/jsteel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jsteel"/>
    <language>en</language>
    <item>
      <title>Fully remote companies are better than hybrid</title>
      <dc:creator>Jonathan Steel</dc:creator>
      <pubDate>Wed, 01 Feb 2023 18:44:42 +0000</pubDate>
      <link>https://dev.to/aha/fully-remote-companies-are-better-than-hybrid-4f53</link>
      <guid>https://dev.to/aha/fully-remote-companies-are-better-than-hybrid-4f53</guid>
      <description>&lt;p&gt;I have worked in many different environments throughout my career. I have worked in the same building as my teammates and even for a company that had us all in the same room. I have also worked in hybrid environments with a mix of in office and remote employees. In the hybrid case, I was always onsite. I had never been on the other side, where I was remote and there were other people physically together. And in my five years &lt;a href="https://www.aha.io/blog/my-name-is-jonathan-steel-this-is-why-i-joined-aha" rel="noopener noreferrer"&gt;working for Aha!&lt;/a&gt;, I have always been grateful to work for a fully remote company.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I knew I did not want to work in an office anymore and only truly discovered while working at Aha! how great a remote team can be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Fully distributed
&lt;/h2&gt;

&lt;p&gt;Frequent communication and collaboration are invaluable to every group at a company. As an engineering team lead, I know this doesn't come as naturally to some as it does to others. Engineering team members can be especially susceptible to losing contact with the rest of the team and company when they are in a hybrid situation.&lt;/p&gt;

&lt;p&gt;When some people are in person and others are remote it is harder for everyone to succeed equally. Some teams may see the creative work, decision-making, and architecture being discussed without the remote engineer that will do the actual work. Those decisions are encoded in the form of features, tickets, or tasks that flow down to the engineer. If there is any confusion in the work assignments, it may be perceived as a communication error on the part of the remote engineer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When everyone is remote, there are no communication barriers. We are all accustomed to jumping on a video call or sending a quick instant message.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Onsites
&lt;/h2&gt;

&lt;p&gt;Twice a year, our entire company gets together in person for a week at a destination travel location that we call our company onsite. Everyone has an amazing time discussing the product roadmap, meeting with teammates, volunteering through our Aha! Cares program, and enjoying great meals together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlmt4uua8k3y5twix905.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlmt4uua8k3y5twix905.jpeg" alt="Onsite"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In June 2022, Aha! was able to host an in-person onsite for the first time in over two years. Due to everyone's different circumstances, not everyone was able to attend, including me. We have a truly exceptional team that coordinates these events to include everyone as much as possible — whether onsite or offsite. But I was worried what that might look like.&lt;/p&gt;

&lt;p&gt;So what was it like? At Aha!, we go above and beyond with everything we do and this event was no exception. Everyone tried their hardest to make sure we felt included. We even had our own events that were just as memorable as those at the previous offsite.&lt;/p&gt;

&lt;p&gt;But hybrid work events are just not the same. Sometimes it was hard to hear side conversations and the random comments thrown out in the audience that caused a ripple of laughter.&lt;/p&gt;

&lt;p&gt;The positive takeaway from the experience was that it crystallized in my mind the idea that I never want to work for a hybrid company. I don't think hybrid environments can ever work without leaving some team members feeling left out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This onsite (when I was offsite) had me feeling left out in a way that I didn't when we were all in person or all remote.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some aspects of hybrid environments may improve over time. Technology, tools, and processes can always get better. As hybrid environments become more common, people may also become increasingly familiar and comfortable working with remote and colocated team members at the same time. Even with all those improvements, there is no way to include a remote employee in the random dinner a team might share together.&lt;/p&gt;

&lt;p&gt;I am lucky that Aha! will always make a great effort to include each and every team member. And I now know for certain that hybrid will never be as good as fully remote or fully in-person. My &lt;a href="https://www.aha.io/company/team" rel="noopener noreferrer"&gt;teammates at Aha!&lt;/a&gt; are all so passionate and motivated to bring their best to work every day — 100% remote is what works for us. I am more excited than ever to work for a fully remote company and I am especially excited for our next company onsite.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Aha! is happy, healthy, and hiring. Join us!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We are challenged to do great work and have fun doing it. If you want to build lovable software with this talented and growing team, &lt;a href="https://www.aha.io/company/careers/current-openings?category=engineering" rel="noopener noreferrer"&gt;apply to an open role&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>remote</category>
      <category>hiring</category>
    </item>
    <item>
      <title>Service layer for business logic — Organizing code in a Rails monolith</title>
      <dc:creator>Jonathan Steel</dc:creator>
      <pubDate>Fri, 14 Oct 2022 19:10:30 +0000</pubDate>
      <link>https://dev.to/aha/service-layer-for-business-logic-organizing-code-in-a-rails-monolith-40cj</link>
      <guid>https://dev.to/aha/service-layer-for-business-logic-organizing-code-in-a-rails-monolith-40cj</guid>
      <description>&lt;p&gt;Our engineering team builds the Aha! suite using a Rails monolith. We carefully weighed &lt;a href="https://www.aha.io/engineering/articles/embrace-the-monolith-adding-a-new-product-to-aha"&gt;a number of options&lt;/a&gt; before determining that this would provide the most lovable solution for our users and our team. But the discussion does not end with choosing this path for our code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We work hard to build the best monolith possible so we can retain a high velocity and a clean code base.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the foundations of having a successful monolith is to ensure it is well-organized. Having a service layer for business logic can help keep Ruby on Rails code from growing out of control. Whichever framework you use, it will only help organize the common elements. Design a system for organizing your business logic code using well-defined, unambiguous patterns. Read on to learn how we did this for the Aha! suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing business logic
&lt;/h2&gt;

&lt;p&gt;Rails does a great job of giving you a place to put just about any kind of code. When you create a new Rails project, it comes with an elegant predefined &lt;a href="https://guides.rubyonrails.org/getting_started.html#creating-a-new-rails-project-installing-rails"&gt;directory structure&lt;/a&gt;. There is a place for the models, views, controllers, tests, assets, database migrations, and much more. It does have its limitations though. The most common issue that Rails projects run into is how to deal with business logic.&lt;/p&gt;

&lt;p&gt;When you look at tutorials of Rails code, they are usually beautiful, concise, simple, and easy to read. Many real-life projects start out this way as well. But over time, more and more business logic gets peppered into that clean, elegant code. You cannot avoid this business logic because you would not have a program without it. So as your Rails program grows and ages, all these clean areas of code will start to grow and look less and less like the ideal "Hello, world" examples. The question then quickly arises of where this code should go.&lt;/p&gt;

&lt;p&gt;Often this complex business logic will start to collect in the controllers. A very common practice is to push that logic into the models in an attempt to keep the complexity in one spot. The size of your models is going to grow proportionally with the size of your application. Combining all your complicated and most frequently used logic together into a single location that never stops growing is a disaster waiting to happen.  This will start to get painful as your application becomes a monolith and the code becomes unreadable.&lt;/p&gt;

&lt;p&gt;Does Rails have a place for business logic? The &lt;a href="https://guides.rubyonrails.org/v5.2/getting_started.html"&gt;Rails guides&lt;/a&gt; mention the lib directory as a place for extended modules for your application. You'll find some examples of pushing complex code into concerns, but most concerns are for code reuse. That code is still being included in the same places we said not to put the business logic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never force code into a framework if there is no clear place for it — you may have to venture off the Rails instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Business logic attracts complexity and tends to change more frequently than other areas of your code. This creates the perfect breeding ground for bugs and regressions. Any solution should isolate the business logic, making it easier to test and accelerate future changes. When file size increases proportionally with the application size, your code is destined to be hard to read, understand, and modify. The best way to prevent this is to create code that is narrowly focused instead of serving multiple purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a service layer
&lt;/h2&gt;

&lt;p&gt;One concrete solution is to create a service layer composed of small objects that serve specific use cases. A service layer for business logic can help keep Ruby on Rails code from growing out of control. Whether you use Ruby on Rails or another language and framework, that framework will only help organize common elements. Take a cue from your framework and design a system for organizing your business logic code using well-defined, unambiguous patterns.&lt;/p&gt;

&lt;p&gt;A common place to create a service later is in app/services. Each object will usually only serve a single purpose or possibly a few very tightly related purposes. Keeping these objects focused and constrained to a single purpose ensures that no matter how complex your monolith gets, these objects will never get too big. Here is an example of a simple service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ScheduledReportRunner&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_scheduled_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;allowed_to_send_report?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;reply_to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculate_reply_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;ScheduledReportMailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scheduled_report_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply_to&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;deliver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;

    &lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_run&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_frequency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;
    &lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;allowed_to_send_report?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_reply_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class is small and easy to understand, use, and test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;ScheduledReportRunner&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"#send_scheduled_report"&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"delivers a scheduled report mail message"&lt;/span&gt;
      &lt;span class="n"&gt;scheduled_report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ScheduledReportMailer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scheduled_report_message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"support@aha.io"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_call_original&lt;/span&gt;
      &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_scheduled_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"does not send a report that is not allowed to go out"&lt;/span&gt;
      &lt;span class="n"&gt;scheduled_report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scheduled_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_sent_at: &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ago&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ScheduledReportMailer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_not&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scheduled_report_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_scheduled_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"schedules the next run of the report"&lt;/span&gt;
      &lt;span class="n"&gt;scheduled_report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scheduled_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;send_frequency: &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_scheduled_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_run&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_now&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"uses a custom reply_to when necessary"&lt;/span&gt;
      &lt;span class="n"&gt;scheduled_report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scheduled_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_sent_at: &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ago&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;reply_to: &lt;/span&gt;&lt;span class="s2"&gt;"fred@aha.io"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ScheduledReportMailer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:scheduled_report_message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"fred@aha.io"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_call_original&lt;/span&gt;
      &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_scheduled_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduled_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is often useful to return rich domain objects specific to that service object. For example, instead of returning a single value, you can return an object that has a status, error codes, and multiple model objects. That object can then be passed around as a single unit that shows the correlation between the various items inside it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Organizing with a service layer
&lt;/h2&gt;

&lt;p&gt;In a controller, you can wrap all related business logic together into a single object, take the return value, and pass that on to your views. The rich return objects often eliminate the need to have multiple instance variables instantiated and drilled down through your views. Helper code can now be stored in a more appropriate place that is usable by parts of the code other than views.&lt;/p&gt;

&lt;p&gt;Jobs and rake tasks often end up getting pretty complex as well. These should be very thin wrappers that parse arguments and then delegate to a service object. Structuring your code in this way makes it easy to call from the console if somebody wants to run a rake task or job manually. Having small classes also helps immensely with &lt;a href="https://www.aha.io/engineering/articles/from-one-many-building-a-product-suite-with-a-monolith"&gt;testing a monolith&lt;/a&gt;. By simplifying other areas of your application like models, controllers, and jobs, they now become much easier to test as well.&lt;/p&gt;

&lt;p&gt;The service layer also provides isolation from the rest of your Rails code. Isolation is desirable to provide room for experimentation. You can use whatever coding style you want to create these objects without enforcing that structure on other parts of the code. You can use plain old Ruby objects, classic object-oriented inheritance hierarchies, object composition, meta programming, or even some esoteric bash script you wrote years ago. I prefer small and simple plain old Ruby objects, which are easy to follow.&lt;/p&gt;

&lt;p&gt;It also does not matter how you organize files within the service layer, especially at first. As your service layer grows, patterns will emerge and you can reorganize by creating subdirectories and moving files around. But no matter how big or organized this code gets, you can always create a new subdirectory and try out a new experimental approach there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipping a Minimum Lovable Product
&lt;/h2&gt;

&lt;p&gt;Using a service layer helps us to align our work with our team and company goals. We always strive for the &lt;a href="https://www.aha.io/roadmapping/guide/plans/what-is-a-minimum-lovable-product"&gt;Minimum Lovable Product (MLP)&lt;/a&gt;, only shipping features when they are ready from a technical standpoint. An MLP is an initial offering that users love from the start. It should also be loved by the engineers that are working to maintain it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Features cannot just look good on the frontend — they should be well-organized in the background as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The service layer helps you ship strong code the first time. When you are first authoring a feature, it is very simple to take a chunk of code and create a service object out of it. This means you are more likely to do that right from the start instead of waiting to refactor at a later date. If you do need to refactor, it will mean shuffling around code in small isolated objects and files. That is much easier than coming back after your feature is ready and trying to collect up all the logic you sprinkled around in models, controllers, and views. The service layer is so easy to use that you will feel guilty pushing up a pull request with code where it should not be.&lt;/p&gt;

&lt;p&gt;If used properly, the service layer will help keep your Rails code looking like the simple examples of the Rails guides. It helps to &lt;a href="https://www.aha.io/engineering/articles//2022-09-02-technical-debt-technically-not-debt"&gt;avoid technical debt&lt;/a&gt; and allows Rails to accomplish what it was built for. It also helps reduce the complexity of implementing, maintaining, and testing business logic. It will help you deliver great features with your growing monolith and keep you happing while doing it.&lt;/p&gt;

&lt;p&gt;We will continue to evolve our monolith and make alterations to the architecture to meet our growing needs. Read our other posts on how we chose to utilize a monolith for the Aha! suite:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.aha.io/engineering/articles/from-one-many-building-a-product-suite-with-a-monolith"&gt;From One, Many — Building a Product Suite With a Monolith&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.aha.io/engineering/articles/embrace-the-monolith-adding-a-new-product-to-aha"&gt;Embrace the monolith: Adding a new product to Aha!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sign up for a free trial of Aha! Develop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aha! Develop is a fully extendable agile development tool. Prioritize the backlog, estimate work, and plan sprints. If you are interested in an integrated &lt;a href="https://www.aha.io/suite-overview"&gt;product development&lt;/a&gt; approach, use &lt;a href="https://www.aha.io/product/overviewhttps://www.aha.io/product/integrations/develop"&gt;Aha! Roadmaps and Aha! Develop together&lt;/a&gt;. Sign up for a &lt;a href="https://www.aha.io/trial"&gt;free 30-day trial&lt;/a&gt; or &lt;a href="https://www.aha.io/live-demo"&gt;join a live demo&lt;/a&gt; to see why more than 5,000 companies trust our software to build lovable products and be happy doing it.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>hiring</category>
      <category>onboarding</category>
    </item>
  </channel>
</rss>
