Summarized using AI

Keeping the Rails Magic Alive After 18 Years

Wade Winningham • July 08, 2025 • Philadelphia, PA • Talk

Overview

Wade Winningham, a principal developer at Power Home Remodeling, presents the long-term journey of maintaining and growing a Ruby on Rails application—Nitro—over 18 years, expanding it from a simple app to an enterprise system with over three million lines of code. The talk covers strategies adopted for sustaining large Rails apps, especially focusing on the 'Build vs Buy' philosophy, migration to a Component Based Rails Application (CBRA), and open source tools created along the way.

Key Points

  • Origins and Growth of Nitro

    • Nitro started in 2007 with Rails 1.2.3, replacing manual processes and siloed tools with a centralized application.
    • Over time, the app expanded to cover various business operations, growing immensely in code size and complexity.
  • Build vs Buy Philosophy

    • Power Home prefers building in-house solutions over subscribing to external services when they make business sense, especially for core operations.
    • Examples include developing custom recruiting systems, project management tools, messaging apps, and even hosting in their own cloud.
    • The rationale includes owning data, tighter integration, avoiding vendor lock-in, and customizing features to exact business needs.
    • Acknowledges the increased development and maintenance costs, but values predictability and control.
  • Transition to Component Based Rails Application (CBRA)

    • Faced with monolithic complexity and long CI build times, Power Home modularized their application using the component-based approach outlined by Stefan Hagemann, preceding tools like Packwerk.
    • Modularization included splitting code into Rails engines (components), decoupling dependencies, and iteratively extracting reusable parts.
    • The transition resulted in significant CI/build time improvements (up to 90% faster), better code organization, and ability to extract standalone applications.
    • Continued support and adoption of CBRA, even as the community shifted towards Packwerk, due to investment in tooling and cultural alignment.
  • Open Source Tools and Contributions

    • Shared several internally-developed tools beneficial for Rails and CBRA users:
    • cobra_commander: CLI tool for managing components, especially helpful in bundle updates and dependency mapping.
    • power-tools: A suite of utility gems, addressing challenges like schema management (edge_stitch) and authorization (consent).
    • Playbook Design System: A Rails, React, and Swift compatible UI design system not based on Tailwind CSS.
    • These tools are available as open source, with encouragement for community feedback and contributions.

Notable Case Studies and Anecdotes

  • Migrating away from out-of-business SaaS products (e.g., Applicant Tracking, Pivotal Tracker) prompted the shift towards bespoke solutions.
  • Hosting messaging and business apps in their own private cloud avoids unpredictable costs of external providers.
  • Internal milestones, like reducing build times and extracting fully decoupled services, demonstrate practical results of their strategies.

Conclusion & Takeaways

  • Long-term success with Rails is achievable by investing in modularization, in-house skill development, and open source tooling.
  • The 'Build vs Buy' decision should be intentional and context-driven, balancing innovation, control, and cost.
  • CBRA, though more demanding than newer solutions like Packwerk, can deliver substantial benefits in scalability and maintainability, especially when supported by robust tooling and organizational culture.
  • Open source contributions from large-scale, long-running Rails projects can help the wider community tackle similar challenges.

Keeping the Rails Magic Alive After 18 Years
Wade Winningham • Philadelphia, PA • Talk

Date: July 08, 2025
Published: July 23, 2025
Announced: unknown

Hear from someone who wrote the first line of code for a Rails app started in 2007 that's over 3 million lines of code today. Learn from our journey migrating to a Component Based Rails Application (CBRA) and tools we've open sourced along the way which you may not have heard about, but can help with any Rails application.

Our mantra is Build vs Buy. Learn what that means and if it makes sense for you. We've built our own messenger app, telephony services, support ticket system, project management software, and other apps. Why would we build stuff rather than buy or subscribe to existing apps? We even built our own cloud. I'll explain the experiences that set us on that path.

Our ongoing journey towards a Component Based Rails Application (CBRA). An application of fully gem/engine-based components. I'll discuss lessons learned and why we persist with CBRA when everyone else with a Rails monolith app is going with Packwerk.

Open source tools we've built and how they can help any Rails application. We have a number of public gems and tools like cobra_commander, which helps manage Component Based Rails apps, power-tools, a collection of utility gems useful in any Rails app, and, last but not least, our Playbook Design System which is full design system for Rails, Swift, and React. RailConf will be the first place we've ever talked about these publicly.
At the end, hopefully attendees walk out more confident in choosing Rails for the long haul, armed with knowledge and tools that helped our company go big and keep up with the scale of our growth.

RailsConf 2025

00:00:16.800 Welcome. My name is Wade Winningham and
00:00:18.880 I'm a principal developer at Power Home
00:00:20.800 Remodeling.
00:00:27.680 So from the people here who are not from
00:00:29.920 power,
00:00:31.439 uh how many of you guys have worked on
00:00:33.920 the same Ruby application for like over
00:00:36.239 five years?
00:00:38.239 Wow, that's that's a few but not as many
00:00:40.000 as I thought. So how about 10?
00:00:42.719 Anybody longer than that? That's Wow,
00:00:45.840 just a couple. Wow. So
00:00:48.960 I've been working on P's application for
00:00:51.440 18 years now. We started in 2007. So,
00:00:54.320 this is what literally my 18th year with
00:00:56.320 it. And I'm here today to tell you a
00:00:59.280 little about Power um and Nitro, the app
00:01:03.199 that powers our business. Um a policy
00:01:06.960 that's led to its growth that's a little
00:01:08.640 bit controversial. Um how we modularized
00:01:11.600 it and then showcase some of our open
00:01:13.280 source projects that uh maybe you guys
00:01:15.280 can get uh into your own applications.
00:01:19.200 So, Power's been in business since 1992.
00:01:22.400 So, what does Power actually do? We sell
00:01:25.680 windows, door, siding, and solar
00:01:27.759 solutions to existing homeowners. Um,
00:01:30.960 Power is actually a very employee
00:01:33.040 focused company. As Jenny Gay said
00:01:34.640 earlier, we say we don't hire people to
00:01:37.040 sell windows, but rather we sell windows
00:01:38.960 to hire people. And when someone asks
00:01:41.439 where I work, and I tell them I work in
00:01:43.600 a place that sells windows, doors, and
00:01:46.240 siding, I can see on their face if this
00:01:48.560 is where they think I work.
00:01:52.079 Um,
00:01:54.079 guaranteed that's the reaction I get
00:01:55.680 from people. Um, now these photos are
00:01:57.920 from one of our warehouses, but it's not
00:01:59.840 where we actually have office space. We
00:02:02.159 do have an headquarters that's down the
00:02:04.159 road here outside of Philadelphia. Um,
00:02:06.320 it is in actually a former power plant,
00:02:08.640 which is kind of cool. And, um, we do
00:02:11.200 have a lot of offices around the
00:02:12.640 country. Um, and our HQ
00:02:16.239 is the base of operations for our
00:02:18.720 business technology team. many of them
00:02:20.800 are here. Um, we are like a tech company
00:02:23.760 with empowered where we build Nitro and
00:02:26.879 we think of it as the operating system
00:02:28.800 for our business. It's primarily built
00:02:31.599 with Ruby, Rails, MySQL, some Postgress
00:02:35.519 mostly for GIS capabilities, TypeScript,
00:02:38.560 React and Swift for our mobile
00:02:39.920 applications.
00:02:41.760 Now, Nitro started on Rails 1.23
00:02:46.640 like on 2007. I guess that was the
00:02:49.040 current version back then. Uh so we've
00:02:51.120 been through quite a number of Ruby and
00:02:52.640 Rails upgrades over the years. And this
00:02:55.360 is literally the timeline of all our
00:02:57.280 upgrades for Ruby and Rails over those
00:02:59.040 years. It's something we keep as part of
00:03:01.040 presentations that we give even today.
00:03:03.440 And I just wanted to give a big shout
00:03:05.040 out to fast ruby.io andabs who's helped
00:03:07.840 us through a lot of the upgrades from
00:03:09.680 four through six which were some painful
00:03:11.760 ones for us but uh they were a huge help
00:03:13.599 and so we heartfeltly recommend them
00:03:16.159 whenever we can.
00:03:18.879 Now, when we started back in 2007, Power
00:03:22.640 had nothing but spreadsheets and a
00:03:24.879 single user app that was written in
00:03:26.879 Microsoft Access. Um, and it just was
00:03:30.080 not uh keeping track with them. They
00:03:33.280 literally had to yell down the hall to
00:03:34.879 get people to get out of the app to make
00:03:36.400 any changes.
00:03:38.239 And um while that was a pain, one of the
00:03:40.560 biggest pains was that the sales
00:03:43.040 director would spend nights and weekends
00:03:45.440 updating individual spreadsheets for
00:03:47.519 sales rep statistics so that he could
00:03:49.599 mail them out every single morning to
00:03:51.200 all of his reps. Um that wasn't really a
00:03:54.720 particularly good use of his time. So um
00:03:58.319 they needed a way to basically you know
00:04:00.319 centralize that data and make it
00:04:01.760 accessible and scalable which resulted
00:04:04.879 in this their very very first page of a
00:04:07.599 Ruby on Rails app. It was me starting
00:04:10.000 this thing and within like a month they
00:04:12.159 had this up and running and they were
00:04:13.599 extremely happy. Um now that was really
00:04:16.720 small but you know now anybody could log
00:04:19.919 in and see their stats on any day and
00:04:22.240 the data was imported from their
00:04:23.600 existing system. So, it was really bare
00:04:25.440 bones, but it kind of uh lit a fire
00:04:28.000 under them. Now, looking at that same
00:04:31.040 page today, it's got a lot of different
00:04:33.199 things on it and it's expanded quite a
00:04:35.360 bit and uh we just basically molded it
00:04:38.479 over the years uh to keep up to date
00:04:40.400 with the increasing demands of the
00:04:42.400 business and the employees.
00:04:45.280 Now, that obviously went through a lot
00:04:47.600 of growth. Um, and our app overall to
00:04:50.720 drive the entire business has grown a
00:04:52.479 lot over the years. And from that first
00:04:54.800 page to today, Nitro currently has over
00:04:57.680 three million lines of code of Ruby
00:04:59.680 code. Um, and that's not including some
00:05:02.240 apps that we've split out of our
00:05:03.440 monolith. Um, and while it's grown
00:05:06.000 simply by adding features throughout the
00:05:07.919 entire business, I want to talk today
00:05:10.720 about a policy we have that has helped
00:05:12.240 us grow about to a code base this size.
00:05:15.280 And whenever it's brought up in
00:05:16.639 candidate interviews and with people we
00:05:18.720 talk to, it causes them to raise an
00:05:20.720 eyebrow. And that's our policy on build
00:05:23.280 versus buy. Um, now this isn't a strict
00:05:26.800 rule, but when it makes sense for the
00:05:28.479 business, we prefer to build something
00:05:30.800 ourselves rather than buy it. Now, this
00:05:34.080 can be controversial. U, the Sidekick
00:05:36.479 Wiki has a page all about why building
00:05:38.400 something yourself is going to cost
00:05:40.400 significantly more than buying it. And
00:05:42.560 in the context presented, Mike's right.
00:05:46.639 But buying a service or software isn't
00:05:48.960 always the best for your business.
00:05:52.320 It can be a bit of a minefield um with
00:05:55.360 confusing pricing plans that initially
00:05:57.280 sound great but result in outrageously
00:06:00.240 large bills later down the road.
00:06:03.199 We like to say we put our culture in
00:06:05.039 code. And when you build an app for your
00:06:07.520 business, you have to learn how your
00:06:09.840 business truly works.
00:06:11.840 You get knowledge you'd never gain by
00:06:13.840 trying to squeeze your app into somebody
00:06:15.600 else's. You get control over what your
00:06:18.240 business needs and when they need it.
00:06:20.479 And you're not making processes suffer
00:06:22.319 because of generalized software. And
00:06:24.960 your business is going to grow. And as
00:06:27.600 you scale, the services you use
00:06:29.440 typically will cost much more as you do.
00:06:33.600 Surprise. Price increases from outside
00:06:35.440 systems can be attacks on your on your
00:06:37.440 business. And for a business our size, I
00:06:39.600 could add hundreds of thousands of
00:06:41.120 dollars to cost all the support features
00:06:43.280 we never asked for or even need in some
00:06:45.280 cases.
00:06:47.440 An example of what I'm talking about is
00:06:49.039 around job applicants. Now, these are
00:06:51.759 some screenshots of just a handful of
00:06:53.360 sites that I found of companies that
00:06:55.600 help you manage your recruiting process.
00:06:58.240 We used to use one of them, but then one
00:07:01.120 day we got an email saying, um, we're
00:07:04.160 going out of business in 30 days. uh get
00:07:06.639 your data and so long. So we didn't feel
00:07:11.199 like getting put into that same
00:07:12.479 situation again with another company.
00:07:15.280 And so since our trust was shot,
00:07:19.120 fortunately we were able to pay them to
00:07:20.960 keep their service running while we
00:07:22.319 built our own solution.
00:07:24.720 And in six months with a team of three
00:07:26.560 developers with Ruby on Rails, we built
00:07:28.800 our own recruiting system that's now
00:07:31.120 better for us, more tightly integrated
00:07:33.280 with our systems. It's better than
00:07:35.280 anything we could buy and we continue to
00:07:36.960 make it better every day. We're not
00:07:39.520 paying for features we'd never use. It's
00:07:41.840 exactly what we need and we own our own
00:07:44.800 data and obviously with uh job applicant
00:07:47.520 data, candidate information, um there's
00:07:51.280 security concerns around that. So,
00:07:52.639 keeping track of our own data is we feel
00:07:54.639 more secure about that and we don't
00:07:56.720 worry about us going out of business.
00:07:59.039 Recruiting is just another part of
00:08:00.400 Nitro.
00:08:02.319 Another example of a place that went out
00:08:04.240 of business is Pivotal Tracker. Did
00:08:06.639 anybody ever use Pivotal Tracker? A
00:08:09.360 number of you. Um, so we used it a long
00:08:12.080 time ago. Um, and if you I guess if
00:08:15.280 anybody's there, this they don't even
00:08:16.960 have a site anymore. So hopefully you're
00:08:18.479 able to get your data. Um, but based on
00:08:21.120 past experience, we weren't very
00:08:22.720 inclined to just move to a different
00:08:24.080 product. Does anybody here use Jira now?
00:08:27.840 Wow. A few. Do do you like it?
00:08:31.039 I don't see any hands. Wow.
00:08:34.000 So, yeah. So, you know, and even if you
00:08:37.919 haven't used Jur, do you have work in a
00:08:39.919 place where one department uses one tool
00:08:41.519 and another uses something else? Like
00:08:43.599 one place uses a Google doc, another
00:08:45.839 maybe a sauna in another department.
00:08:49.200 I mean, that's that's just I don't know
00:08:51.600 just not very consistent. So instead of
00:08:54.000 moving to another service, we built
00:08:55.600 runway and had our first version up in
00:08:58.320 Ruby on Rails with four devs and four in
00:09:00.720 yeah four months. Um and outside of the
00:09:03.920 whole trust issue, why build it? Um you
00:09:07.360 know what we do is we think that what we
00:09:11.200 use to plan and build our software
00:09:13.120 contains really important intellectual
00:09:15.040 property that we don't want to lose. So
00:09:18.320 and our soft we're on the last track
00:09:21.200 now. We wanted our entire business to
00:09:23.519 learn to use agile. So using the same
00:09:25.200 tool across the company um has helped
00:09:28.240 teach everybody how to work with agile
00:09:30.880 the same way as our business technology
00:09:32.399 teams. Different departments don't use
00:09:35.040 their own software and we never have to
00:09:37.040 buy more licenses.
00:09:38.959 Now it's not nearly ready yet, but we do
00:09:41.120 have an eye towards open sourcing this
00:09:42.560 one day.
00:09:45.120 Now we don't exclusively build software
00:09:47.440 from scratch. We do use and support open
00:09:49.440 source. Um, the current version of our
00:09:52.240 messaging app, which is called Connect,
00:09:53.680 is built on top of Matrix, which is open
00:09:56.320 source. So, why not use Slack or
00:09:58.640 Discord? We're a really communicative
00:10:01.440 and distributed business, and we want
00:10:03.760 secure messaging and something tightly
00:10:06.160 integrated with our systems.
00:10:09.120 For example, Power has an awesome people
00:10:10.800 experience department. Um, and they plan
00:10:13.279 a lot of events during the year and more
00:10:15.440 events than there are weeks in the year.
00:10:17.519 And anything around events is
00:10:18.800 customization. Most messaging clients
00:10:21.040 don't support without a lot of
00:10:22.320 development effort already. So Slack and
00:10:24.800 Discord are great, but rolling our own
00:10:26.560 allows us to keep control of our own
00:10:28.000 data and build the features we need.
00:10:31.040 And we even host in our own cloud on our
00:10:33.120 own data data centers. We don't use
00:10:35.200 Azure or Google or AWS.
00:10:38.320 Is it easier to use them? Probably. They
00:10:41.279 just come with all those confusing
00:10:42.560 pricing models I mentioned earlier. And
00:10:44.640 the slightest changes of those pricing
00:10:46.480 models can have a really serious huge
00:10:48.720 impact on your budget. And if you're
00:10:50.959 wanting to scale your business, we think
00:10:53.040 it's better to hire smart people than to
00:10:55.440 have other people sell you theirs. We
00:10:58.079 kind of see hosting services as their
00:10:59.680 own tax. You host your software with
00:11:02.560 them, even software you write, and then
00:11:05.120 they charge you for it. That's kind of
00:11:07.519 our view and why we host our own stuff.
00:11:10.560 Now, we don't do this for everything. If
00:11:12.320 it's not core to our business, we'll
00:11:14.480 certainly use outside services that best
00:11:16.560 suit our needs. In a lot of these cases,
00:11:18.959 it's best for them it best for them to
00:11:20.720 be hosted outside of our infrastructure
00:11:22.240 anyway, so if something goes down, we
00:11:24.160 still have access to information to help
00:11:25.920 us diagnose what's happening.
00:11:29.200 We like to invest in the people and
00:11:30.880 applications that give us customized
00:11:32.480 solutions where we own our own data.
00:11:35.680 Does this cost more long term? Likely,
00:11:38.720 but with less surprises. And although
00:11:41.200 Rails allows us to deliver relatively
00:11:43.200 quickly, you still need time to develop
00:11:46.079 and m and maintain, you know, for
00:11:48.399 ongoing feature development,
00:11:50.880 but but we own our own destiny and we're
00:11:52.880 investing it in ourselves rather than
00:11:54.480 organizations that don't even know us.
00:11:57.600 Now, is this for everybody? Of course
00:11:59.360 not. Um, you have to do what makes sense
00:12:01.839 for you and consider the risks. We don't
00:12:04.320 just jump out of the gate and start
00:12:05.680 building stuff, but it's always on the
00:12:07.200 table. But if you're growing, then you
00:12:09.920 are going to be the best at growing both
00:12:11.760 your business and your software.
00:12:14.800 Now, after many years of building and
00:12:16.800 growing, Nitro grew into a monolith.
00:12:20.560 A large code base leads to a lot of
00:12:22.399 problems. And at our worst point, our CI
00:12:24.880 builds literally took four and a half
00:12:26.800 hours for a single build. Not to mention
00:12:29.519 problems with code organization.
00:12:32.399 So, who's here heard of Packwork?
00:12:35.760 Uh, good number of people.
00:12:38.079 if you haven't, it's all about
00:12:39.440 compartmentalizing large monoliths like
00:12:41.760 Nitro. However, packwork wasn't a thing
00:12:44.560 when we needed to start doing this. At
00:12:47.279 that point, um Stefan Hogaman's original
00:12:50.240 book on the topic was component-based
00:12:52.399 Rails applications or Cobra.
00:12:55.440 It was in beta, but we dove into it
00:12:57.920 anyway. Um does anybody use or have an
00:13:02.160 application written with, you know, as a
00:13:04.399 component-based Rails application? Wow,
00:13:07.920 a couple. I'm really surprised. That's
00:13:10.160 awesome. So,
00:13:13.440 I asked because I met Stefan last year
00:13:15.600 at Railscom and he seemed really
00:13:17.920 surprised and excited to see what we've
00:13:19.920 done with Cobra.
00:13:22.480 So, by the t time packs was introduced,
00:13:26.240 we had already had years behind us with
00:13:28.079 Cobra. And while most seem to have
00:13:30.560 abandoned it, and obviously there's, you
00:13:32.240 know, a few, you know, stragglers here,
00:13:34.320 that's awesome.
00:13:36.000 um we stuck with it and having paid the
00:13:38.560 time and cost by generating the tools,
00:13:40.880 generators and docs around setting up
00:13:43.040 new components, it's become part of our
00:13:45.519 everyday workflow. Now, for time, I'm
00:13:47.920 going to keep things at a high level,
00:13:49.040 but I want to talk about the differences
00:13:50.560 between these two and what's common
00:13:52.000 between them.
00:13:54.399 So, today if your app has grown to what
00:13:57.040 you call a monolith and you want to
00:13:58.880 check out pack uh you want to modularize
00:14:01.600 it, you should check out packwork. It's
00:14:04.399 called gradual modularization for a
00:14:06.880 reason. Um, I had to practice that a lot
00:14:10.000 saying modularization because that's a
00:14:12.000 really hard word to say. Um, now based
00:14:14.560 on this note on the Cobra website,
00:14:15.839 Hogerman itself would agree that yeah,
00:14:17.920 packwork is what you should probably
00:14:19.279 start with. Um, it just provides a lower
00:14:22.639 barrier of entry. So, I'm not here today
00:14:25.040 to try to convince you to use Cobra over
00:14:26.880 pack, but rather to show you the
00:14:28.320 differences along with some tools that
00:14:29.680 we've written to help manage things.
00:14:32.320 Now, at a high level,
00:14:34.639 packwork initially helps organize your
00:14:36.399 app folder into packs directories. Now,
00:14:39.040 at this stage, you're just moving files
00:14:40.720 around and your packs of related code
00:14:43.600 still rely on the gems and configuration
00:14:46.399 of your overall application.
00:14:49.279 Pack works tools help you identify and
00:14:52.320 deal with interaction between packs to
00:14:54.639 prevent circular dependencies and
00:14:56.399 isolate a pack code. And if you're just
00:14:58.880 organizing code, you can stop here. Many
00:15:01.279 who start, this is where they stop. They
00:15:03.199 don't ever make it get past this stage.
00:15:06.240 But if your goal is to eventually lift
00:15:09.600 your pack outside of your app into its
00:15:12.000 own app and repo, you need to take it to
00:15:14.720 the next step and make it a Rails
00:15:16.079 engine. It still is in the same place,
00:15:19.120 but it's now its own self-contained mini
00:15:21.120 Rails app with the configuration and
00:15:22.800 setup it needs in order to survive as a
00:15:24.959 Rails engine that lives outside of your
00:15:26.720 app.
00:15:29.519 And then once your pack is an engine and
00:15:32.079 your app's integrations with it are
00:15:33.600 ready, you can lift it out into a
00:15:35.199 completely separate app. Now that makes
00:15:37.040 it sound a lot easier than it really is,
00:15:38.720 but but the at a high level that's the
00:15:41.120 steps you have to go through. Um,
00:15:44.800 component-based Rails apps go straight
00:15:47.120 to a Rails engine. Both help you make
00:15:49.920 the transition from monolith to separate
00:15:51.600 repos easier because you can tackle
00:15:53.759 decoupling iteratively rather than all
00:15:56.399 at once.
00:15:58.800 The runway project I mentioned earlier
00:16:00.399 is an example of an app we extracted
00:16:02.560 outside of our nitro monolith. It used
00:16:05.279 to be a component but was lifted out and
00:16:07.360 now survives in its own repo and
00:16:09.519 application. So that's the first step in
00:16:11.360 making it open source. Now we just have
00:16:12.959 to u make it a generalized app that
00:16:16.480 anybody could use.
00:16:19.120 Now Cobra seems like a harder approach.
00:16:21.040 That's because it is. But recall we
00:16:23.440 started way before Packwork existed and
00:16:26.000 we really dedicated ourselves to the
00:16:27.839 journey. Now there's no magic wand. Um
00:16:31.680 you don't just start using it and fix
00:16:33.199 all your monolith problems. You have to
00:16:35.839 have a very strong commitment from the
00:16:37.920 business and your development team.
00:16:40.560 Packwork and Cobra require devs to
00:16:42.560 rewire your brains a bit from what
00:16:44.320 you're used to working with a normal
00:16:45.680 Rails app.
00:16:47.680 um you need to treat how code interacts
00:16:49.680 between packs or components similar to
00:16:51.440 how they would be as if they were
00:16:52.560 external services because if you're
00:16:54.480 going to lift them out it's going to be
00:16:55.920 an external service. So
00:16:59.600 decoupling components and libraries
00:17:02.079 requires a lot of time and that's why
00:17:04.079 you need the business support. Now, we
00:17:06.160 started this journey about eight or nine
00:17:07.679 years ago, and today all of our teams
00:17:09.839 are led by a lead developer who's
00:17:12.160 experienced enough to help guide new
00:17:13.919 team members so that we're always on our
00:17:16.160 path. We just made it part of our
00:17:18.480 culture. And as I said earlier, we put
00:17:20.160 our culture in code.
00:17:22.559 Now, you obviously begin with your first
00:17:24.400 component, and we chose this
00:17:26.640 intentionally long and nasty looking
00:17:29.039 name to boost our desire to get rid of
00:17:31.360 it.
00:17:32.880 Um, the benefits of doing just this
00:17:34.880 though is pretty underwhelming.
00:17:37.120 Everything being in one place really
00:17:38.880 wasn't impacting our 4-hour build times.
00:17:41.840 So, for a quick win, we decided to move
00:17:44.160 all of our models into their own
00:17:45.600 component to split up our codebase. And
00:17:48.080 by running two component tests in
00:17:49.760 parallel, we got a 50% buildtime
00:17:52.559 improvement. So, that was cheating, but
00:17:55.600 it gave us the confidence to keep moving
00:17:57.280 forward.
00:17:58.880 Now, this diagram logistically shows our
00:18:01.440 real starting point for flattening out
00:18:03.200 our initial gargantuan application. And
00:18:06.240 it didn't take long before things looked
00:18:07.840 more like this, which is part of what
00:18:10.080 Packworking uh Cobra helped manage the
00:18:12.799 complexity that you start to grow. Now,
00:18:15.120 this diagram is it's dense enough today
00:18:17.520 that it would not be discernible on the
00:18:19.520 screen. U so this was just an example of
00:18:23.039 something from a long time ago.
00:18:28.240 So something that makes it a lot easier
00:18:29.760 for us is a generator for bootstrapping
00:18:31.919 new components. Um existing libraries
00:18:34.799 that make it straightforward to jump
00:18:36.240 into development quickly and
00:18:38.160 documentation that walks developers
00:18:40.720 through what they need to know without
00:18:41.919 any friction.
00:18:44.320 Our build times today are about 90%
00:18:46.960 faster in some cases than at our worst
00:18:49.039 point. And surprisingly, it's getting
00:18:51.280 better even with a still growing code
00:18:53.760 base. Now, this is partly because we can
00:18:56.320 check a PR's code changes and determine
00:18:59.039 what components it affects and only
00:19:01.600 execute tests in those components. We've
00:19:04.720 also made tests more efficient. And a
00:19:06.400 huge shout out to Evil Martians. They're
00:19:07.840 getting a big shout out shout out at the
00:19:10.080 conference this year. Um, they helped us
00:19:12.240 reduce some build times with some of the
00:19:13.840 techniques and they use for uh for, you
00:19:15.919 know, test running and stuff. We're
00:19:18.720 still striving to shrink it further, but
00:19:20.480 uh but it's it's headed in a very good
00:19:23.200 direction.
00:19:25.200 Now, upgrading a monolith with that's
00:19:28.240 built on Cobra is obviously more
00:19:30.720 complicated, but it's primarily dealing
00:19:33.120 with merge conflicts and gyms that need
00:19:35.200 updating.
00:19:36.799 Updating gym files entails running
00:19:38.400 bundle update across all your
00:19:41.120 components. So, if you've got 160 of
00:19:43.679 them, that's a lot of bundle updates you
00:19:45.760 have to run. But, we do have a tool to
00:19:47.679 help manage that that I'll mention
00:19:48.799 shortly.
00:19:50.640 So this is a little list of some of the
00:19:52.240 stuff we get from Cobra over Packwork,
00:19:54.640 but when it comes down to it, we've
00:19:56.000 gotten faster build times and we've
00:19:58.160 finally realized the ability to extract
00:20:00.160 code out of our monolith. Both help our
00:20:02.640 developers ship faster and why power at
00:20:05.039 a business level continues its support.
00:20:08.480 So why not just use packwork installing
00:20:10.799 and quit calling a Cobra? We're
00:20:12.960 basically starting at step two of co of
00:20:14.880 pack work. So that's a good question.
00:20:17.200 it. We simply hasn't made it a priority
00:20:19.919 to investigate. But I am hoping to chat
00:20:22.160 with some of the packwork folks here at
00:20:24.000 Rubcom tomorrow to see if that's
00:20:26.160 something worth investigating.
00:20:28.799 After all, we do use packwork as a
00:20:30.880 double check to make sure we cover
00:20:32.080 undeclared and circular dependencies.
00:20:33.919 But this is just part of our build
00:20:35.200 process. Now,
00:20:37.760 now I mentioned that we have some tools
00:20:40.240 that help us be efficient. I want to
00:20:42.640 shift gears a bit to talk about some
00:20:44.000 open source projects we've created and
00:20:45.840 some of these are Cobra related but not
00:20:47.520 all of them.
00:20:49.440 So Cobra Commander
00:20:51.679 is a command line tool for Cobra
00:20:53.679 applications.
00:20:55.440 Um I used it earlier to show our
00:20:57.039 component count.
00:20:59.520 Um it can list component dependencies,
00:21:01.840 display a tree of them and orchestrate
00:21:04.080 commands to run within all components, a
00:21:06.400 single component or a component in its
00:21:08.080 dependencies. It's a great tool,
00:21:10.080 especially when updating your Ruby or
00:21:11.520 Rails versions. Um, for example, we can
00:21:13.679 use it to perform a B bundle update
00:21:15.600 across all of our components with a
00:21:17.280 single command. So, it makes it
00:21:19.039 incredibly useful when we're doing that.
00:21:22.320 And, um, you can I had to zoom in a lot,
00:21:25.200 but I I did like a graph of our
00:21:27.200 recruiting component, and I, like I
00:21:30.159 said, you couldn't it looked like a
00:21:32.080 smudge if you zoom out to see the whole
00:21:34.559 thing, but I tried to zoom in as best I
00:21:37.120 could.
00:21:40.000 So, Power Tools is actually a collection
00:21:42.159 of useful gems for all of our apps. Some
00:21:44.559 are Cobra, some are not, but there's a
00:21:47.200 lot of them. So, I encourage you to go
00:21:48.880 check it out if you want. Uh, I'm just
00:21:50.960 going to focus on a couple.
00:21:54.240 So, one issue that a monolith has is a
00:21:56.559 bloated schema file, and it's prone to
00:22:00.159 merge conflicts. Now, edge stitch breaks
00:22:03.760 up our schema by component into partial
00:22:06.080 schemas. Nitro has over 1,500 tables and
00:22:10.720 you can only imagine the amount of churn
00:22:12.559 having a single schema file would have.
00:22:14.799 I think I I'm pretty sure our developers
00:22:17.200 would revolt.
00:22:18.880 Um but we believe that a component that
00:22:21.120 owns a model should own its underlying
00:22:23.520 schema. So when performing database
00:22:26.159 operations, edge stitch stitches the
00:22:28.799 schema partials of a component and its
00:22:31.360 dependent components into exactly the
00:22:34.080 schema it needs. This helps with those
00:22:36.880 nasty merge conflicts quite a bit
00:22:38.799 because our schema is broken up across
00:22:40.559 components. And if you're curious why
00:22:42.559 this is SQL versus Ruby format, it's
00:22:45.280 because at one time you could update a
00:22:48.080 schema with information that Rails
00:22:49.760 couldn't replicate with schema.rb and we
00:22:52.080 just simply never changed, never updated
00:22:53.919 it. Uh we think it's schema RB can do it
00:22:56.799 now. So it's something we plan to do at
00:22:58.960 some point to convert it to use either
00:23:00.720 format.
00:23:02.880 Now, consent
00:23:05.039 is a gym that helps build a dynamic
00:23:07.200 authorization system that persists
00:23:09.520 permission assignments to the database.
00:23:11.520 It's built on top of can can. And I
00:23:14.559 guess we chose consent because that
00:23:16.080 sounded better than can can.
00:23:18.960 Um, but it makes it easy to set up
00:23:21.120 complicated permissions. It can be used
00:23:23.600 in any Rails application, not just
00:23:25.679 Packwork or Cobra. And this example, it
00:23:29.760 basically gives a new role permissions
00:23:31.200 to update projects that are only
00:23:32.720 associated within a user's department.
00:23:35.200 So how does that work?
00:23:38.320 This config basically says for a project
00:23:40.880 model, we can allow an update action
00:23:43.520 that can restrict a user to seeing
00:23:45.200 projects for their assigned department,
00:23:46.880 all projects or none in the UI. And
00:23:49.760 basically we store that in the database.
00:23:51.440 So when the uh uh application loads it
00:23:54.960 basically translates all this DSL stuff
00:23:57.440 into a can can can instructions so that
00:23:59.520 you can use it methods its methods
00:24:01.600 normally applying the appropriate filter
00:24:03.440 conditions. So makes it pretty slick to
00:24:06.159 easily add uh permissions and track
00:24:08.240 them.
00:24:10.320 And last but not least is our design
00:24:12.480 system playbook.
00:24:15.760 So, if you like some of the Nitro
00:24:17.840 screenshots I've shown, you can use this
00:24:20.159 same system in your applications.
00:24:22.880 Unlike almost every other UI system out
00:24:25.520 there for Rails, it's not based on
00:24:27.279 Tailwind CSS.
00:24:30.559 I I I see I have a lot of support. Um I
00:24:34.880 I literally looked this up the other
00:24:36.400 day. I'm like, there's literally no
00:24:38.159 other design system that doesn't use
00:24:39.840 Tailwind CSS. I'm like I just want to
00:24:42.159 stab my eyes out. Um, so to me that's a
00:24:46.000 big feature and it sounds like I've got
00:24:47.200 a lot of support. Um, so here's a simple
00:24:50.080 example for a Rails view. So Playbook
00:24:51.919 has allowed our developers to simply
00:24:53.440 drop in UX patterns without even
00:24:55.600 thinking about it. Plus you can use it
00:24:58.720 with React and Swift.
00:25:03.360 So there's a lot in there now, but we'd
00:25:05.440 love to expand it further with your
00:25:06.880 feature suggestions and contributions.
00:25:08.559 So we really encourage you to check it
00:25:10.240 out if you're interested.
00:25:14.080 And if you're curious to look through
00:25:15.279 more, you can check out all the power
00:25:17.840 home gems on Ruby gems. We've got a few
00:25:20.480 there. It's it's just coincidental that
00:25:22.720 I showcased some of the ones that I
00:25:24.320 talked about. I guess alphabetically it
00:25:26.880 was the first ones I encountered.
00:25:30.320 And we do have some open positions, by
00:25:33.279 the way. If you're interested, check us
00:25:35.279 out at our booth in the sponsors area.
00:25:37.120 And if you have questions, I'll hang out
00:25:39.039 here for a little bit. But uh otherwise
00:25:40.880 find me floating around the conference
00:25:42.559 or any one of my colleagues. We'll all
00:25:44.960 be wearing these shirts tomorrow. So we
00:25:47.039 will have a very big uh presence. So
00:25:51.360 look for us. And then thanks for all
00:25:54.159 your time and especially for the
00:25:55.520 RailsCom crew for all their great hard
00:25:57.360 work that they've done for us.
Explore all talks recorded at RailsConf 2025
Ben Sheldon
Sam Poder
Rhiannon Payne
Joe Masilotti
Josh Puetz
Wade Winningham
Irina Nazarova
Tess Griffin
+77