rubyday 2021

ViewComponents in the Real World

ViewComponents in the Real World

by Joel Hawksley

ViewComponents in the Real World is a presentation delivered by Joel Hawksley at RubyDay 2021, focusing on how GitHub has utilized ViewComponents to build scalable, reusable, and testable UI components within their Rails application. Joel discusses both the technical aspects of integrating ViewComponents and the cultural implications of fostering a developer community around these components.

Key Points Discussed:

- Introduction to ViewComponents:

- ViewComponents emerged from the need to manage complex UI in GitHub’s large Rails monolith, which handles tens of thousands of requests per second and contains over 4,700 views.

- ViewComponents enable a structured way to create reusable components similar to React components in a Ruby on Rails environment.

- Scalability Challenges:

- Scaling an application creates challenges, such as identifying which templates render certain parts of a page. To overcome this, GitHub implemented a custom ERB compiler that adds HTML comments to templates, indicating their source.

- Visual changes often require more robust testing than unit tests provide; therefore, Joel’s team created a system test conversion module to improve testing efficiency.

- Development Tools:

- A tool named ViewFinder was developed to map out how templates reference each other, helping developers understand the dependencies and potential impacts of their changes.

- Joel emphasizes that defining clear components helps enforce UI consistency across the application, making UI updates more seamless.

- Performance Improvements:

- ViewComponents help minimize database queries and increase performance by enforcing the understanding of how view logic interacts with the database. This can prevent unnecessary queries and improve efficiency.

- Community Engagement and Open Source:

- The team open-sourced their Primer ViewComponents library, which gained significant interest and contributions from the community, leading to lessons on empathy and accessibility in documentation and contribution processes.

- Future Directions:

- There are ongoing discussions on improving caching mechanisms in ViewComponents and adapting practices from contemporary frameworks like React. Joel emphasizes the importance of continuous innovation to keep Ruby and Rails relevant in a rapidly evolving tech landscape.

Conclusion:

Joel's presentation illustrates that adopting ViewComponents at GitHub has led to significant growth in component usage, improved consistency in UI design, better testing strategies, and heightened performance. The community-driven approach to open sourcing these components has fostered a collaborative and innovative environment, benefiting both GitHub and the wider development community.

00:00:00.120 Oh my gosh.
00:00:33.899 [Foreign]
00:00:47.899 For our next talk, let me introduce you to Joel.
00:01:04.440 Welcome, Joel! Hey, thanks, Monica. Thanks for having me. Thank you for joining us.
00:01:10.680 Well, today we have Joel Hawksley, directly from GitHub, the creator of ViewComponents.
00:01:16.740 And guess what? We're going to be talking about ViewComponents.
00:01:22.220 But the interesting part about this is not only about ViewComponents per se.
00:01:28.380 What I love is that you're going to talk about how to build a community around something new.
00:01:33.479 How do you nurture something like that? How do you open source a library of ViewComponents and actually scale an application to hundreds of them?
00:01:40.140 So, it's going to be not only about theory, but also practice, I guess, and how to bring ViewComponents to life for the whole community.
00:01:47.700 I'll leave the stage to you. Thank you so much again for being with us.
00:01:53.399 Wonderful! Thanks for having me, Monica. I really wish I was with you all in person in Italy, but this virtual experience will have to suffice.
00:02:00.420 Maybe next year we can all be drinking some wine together in some beautiful place in Italy.
00:02:07.740 Anyways, all right. Well, my name is Joel. Thanks for coming to this session.
00:02:12.900 Today, I'm going to share some lessons we've learned building ViewComponents at GitHub over the past year.
00:02:19.440 I'm an engineer on the design infrastructure team at GitHub. We're responsible for the Primer design system.
00:02:25.860 As you can see, it's really a system of systems. We have a CSS framework, React components, and a library of ViewComponents.
00:02:32.060 These are just a few of the pieces that you might expect in a modern design system these days.
00:02:37.560 My job on the GitHub design infrastructure team is to create consistent, accessible, resilient user interfaces in our Rails monolith.
00:02:43.379 We aim to make this an enjoyable experience, all at what I would call an incredible scale.
00:02:49.500 Whenever I give talks about our monolith, people always ask, 'How big is your application?'
00:02:55.860 So here's a few stats: The GitHub Rails app is over 13 years old and receives tens of thousands of requests per second.
00:03:03.480 We've extracted around two dozen services from the application into what many call a citadel architecture.
00:03:10.140 Most of our services are written in Go, addressing functional areas, but most of GitHub you interact with is still a Rails monolith.
00:03:16.670 It's a monolith that continues to grow very quickly.
00:03:23.220 To give you an idea, we have almost 600 models in our application, which has grown by about 33% over the past year.
00:03:28.620 We have almost 4,700 views, growing nearly 20%, and over 800 controllers, with a growth of almost 37% over the last year.
00:03:44.280 Most importantly for our design team, we have over 2,000 pages in the application that need to stay current and up to date with our design standards.
00:03:50.220 This scale creates interesting challenges; what may be a small annoyance in smaller Rails applications can turn into serious roadblocks for us.
00:03:56.459 I'm going to start by sharing some of those serious roadblocks.
00:04:03.660 When you have a body of work this large, patterns begin to emerge, and one challenge we encountered was identifying which template renders which part of a page.
00:04:10.620 For example, on a pull request page, if I want to edit the draft badge displaying the status of a pull request, how do I find the right place to make that change?
00:04:17.400 One way could be searching for specific class names on the element. However, since these class names aren't unique, it's not a very reliable approach.
00:04:25.140 In this case, if you search for these class names, you might receive dozens or even hundreds of results.
00:04:31.740 To address this issue, we decided to add HTML comments at the beginning and end of every template's output, including the path of the template file.
00:04:39.300 To accomplish this, we wrote a custom ERB compiler.
00:04:46.139 The ERB compiler defines a subclass of ActionView template handlers ERB and we define a call method that receives a template object.
00:04:51.479 The first thing we do is take the output of the superclass and assign it to a variable.
00:04:59.520 Then, we grab that template object and render HTML comments using the path attribute before and after the output of the template.
00:05:06.360 After that, we register the compiler as the handler for ERB files.
00:05:12.720 Now we can see which template rendered which part of a page. In this case, it's a ViewComponent we wrote to display the state of a pull request.
00:05:18.780 This annotation feature has been beneficial internally; we actually extracted this into Rails.
00:05:25.560 This is part of Rails 6.1. You can enable it with the configuration variable config.action_view.annotate_template_file_names.
00:05:32.760 If you create a new Rails application today, this annotation feature is enabled by default in local development.
00:05:39.360 Another issue we face at our scale is getting our application into the right state for visual changes.
00:05:46.320 For designers, unit tests often aren't sufficient for verifying visual changes.
00:05:53.100 A lot of these challenges arise from our citadel architecture with multiple services.
00:05:59.520 Although we have a Rails monolith and about two dozen external services, achieving smooth local reproduction can be challenging.
00:06:06.360 You might wonder why we don’t just use system tests. We’ve thought about this, but they can add significant time to our test suite.
00:06:13.740 We write plenty of controller tests, and after collaborating with our designers for a while, we identified a way forward.
00:06:20.520 What if we could convert our controller tests into system tests? That way, we could reuse the existing setup code, stubs, mocks, and fake services.
00:06:27.720 This would allow us to preview our application in a specific state.
00:06:34.440 Here’s what a controller test looks like: it calls 'GET' with a URL and makes an assertion against the response code.
00:06:42.240 To convert this into a system test, we could write a module called SystemTestConversion.
00:06:49.080 When this module is included, it registers basic configuration for ActionDispatch::SystemTestCase.
00:06:56.520 Next, we redefine the 'GET' method to visit the provided path and pause execution with a debugger.
00:07:03.240 Regarding the assert response, we can treat that as a no-op.
00:07:09.420 We then check for a runtime environment variable, which will be designated as running in a browser.
00:07:15.360 If so, we include that module into our base controller test case.
00:07:21.480 This means that we’re effectively converting a controller test into a system test at runtime.
00:07:27.840 Unlike template annotations, this feature hasn’t made it into Rails yet.
00:07:36.360 It’s dependent on our specific architecture, but it has served us well.
00:07:43.020 More generally, we've noticed that our seeds and test setup code have a lot of overlap.
00:07:49.260 I’m curious if there’s a better way we could bridge the gap between these conceptual domains, particularly with external services.
00:07:55.680 While working on these projects, we identified another source of friction.
00:08:02.880 When rendering a template at our scale, it can be difficult to know where it's used.
00:08:09.300 If you’re unaware of where a template is used, changing it becomes risky, particularly when we reuse partials frequently.
00:08:15.030 To better understand this issue, my colleague John Hawthorne created a diagram showing how our templates reference each other.
00:08:21.660 It’s like a massive ball of spaghetti, and navigating this render stack can be quite tricky.
00:08:28.830 This makes it daunting to make changes in these templates.
00:08:36.780 To get a handle on this problem, we built a tool called ViewFinder.
00:08:44.100 Here’s how it works: you pass in the path to a template, for example, the wiki show page.
00:08:52.800 If I made a change to the wiki show page and input the command, it starts by extracting the template string literal.
00:08:59.940 The string literal is 'Wiki show,' and we search for it in the code base.
00:09:06.240 This works similarly to a global text search in an editor.
00:09:12.600 For each of our search results, we load the resulting file with the Parser gem.
00:09:19.140 The parser returns what's called an Abstract Syntax Tree (AST) of the file.
00:09:25.740 For example, here's one of the matches; it happens to be a controller with part of its syntax tree.
00:09:32.639 This data structure represents how Ruby interprets the code we write.
00:09:41.160 RoboCop also works this way; it translates Ruby into these data structures for operations.
00:09:48.600 As you can see, we have our render call to 'Wiki/show,' and we’re doing this parsing step.
00:09:56.160 This confirms that those command-shift-F global search results are render calls to our specific path.
00:10:03.960 We continue this process recursively until reaching a controller action.
00:10:11.760 Once we reach the controller action, we query back up the tree to find the method definition.
00:10:18.840 In this case, we find the definition of the show method, meaning that we are in 'WikiController#show.'
00:10:25.740 From there, we look up the routes that render that controller action, which helps us locate it.
00:10:32.760 Here's the summary: we input 'bin viewfinder' followed by the path to our wiki show template.
00:10:39.960 In the end, we find two routes that route to that template.
00:10:47.520 Both the WikiController#show and the '/repository/wiki' URLs reuse this template.
00:10:54.840 This enables us to know where to go when we want to verify we haven’t broken something in our application.
00:11:01.740 On its own, this tool has been useful; we can see all the routes that rendered a specific template.
00:11:08.760 Moreover, we realized we could link these routes back to identify which controller tests rendered our template.
00:11:15.480 We started by finding all of the 'GET' calls from our controller tests.
00:11:22.740 Here's one that loads the wiki for a given repository.
00:11:30.120 We extract that path and use Rails' routing mechanism to recognize what controller action it maps to.
00:11:37.440 This returns a hash that includes the name of the controller and the action determined.
00:11:44.580 We repeat this process for every single controller test in our suite, creating a hash that we cache heavily.
00:11:52.320 This enables us to include which tests render a certain ViewComponent in our system test conversion tool.
00:11:58.380 We can verify changes to our template in a browser, allowing us to move from knowing the template’s name to providing a test.
00:12:06.840 We can automatically reproduce the page that renders without local setup in my environment.
00:12:13.680 Unfortunately, this only works with explicit render calls where the template name is passed to the render method.
00:12:22.560 This is enforced with a linter we use for other optimizations in the GitHub application.
00:12:30.540 Thus, this approach isn’t universally applicable across all Rails apps. It also doesn't account for conditionals.
00:12:38.820 Nevertheless, it's been extremely helpful, especially for designers making changes that need quick reproduction.
00:12:46.260 The biggest challenge we face as a design infrastructure team has been the missing abstraction in our view layer.
00:12:53.280 A common rule of abstraction is the Rule of Three.
00:13:02.340 One of my favorite Ruby books discusses the Rule of Three, suggesting that the first time you do something, just do it.
00:13:09.240 The second time, you notice the duplication but do it anyway. By the third time, you refactor.
00:13:16.080 When developers repeatedly create similar code without abstraction, it leads to inconsistencies and maintenance difficulties.
00:13:24.180 For us as a Design Systems team, the goal is to enable sweeping changes to designs across GitHub effectively.
00:13:31.920 This duplication makes it hard to have a broad impact.
00:13:38.760 In 2019, I had a crazy idea of using Ruby objects to render views, inspired by React.
00:13:46.440 We now call this ViewComponent, a framework for building reusable, testable, and encapsulated view components as a natural extension to Rails.
00:13:54.060 At its core, a ViewComponent is a Ruby file, often accompanied by a template.
00:14:01.320 The Ruby file contains an initializer that assigns an instance variable, such as a title.
00:14:08.640 The template may include HTML that utilizes the title as an attribute.
00:14:15.060 To render it, we instantiate the component and pass it to the render method.
00:14:22.200 This ability to pass objects to render was a vital change we made to Rails for supporting this framework.
00:14:29.340 We can also pass in content blocks; for example, we can say 'Hello World' in a block.
00:14:37.500 When we render this, we get a span with the title attribute assigned and the block content returns inside.
00:14:44.460 To test the component, we write a unit test that renders the component, asserting against the output.
00:14:51.060 Using matchers from Capybara, these tests are extremely fast.
00:14:57.840 In our code base, they run about 100 times faster than our controller tests.
00:15:04.740 We’re talking about a quarter of a second compared to six seconds for a controller test.
00:15:11.640 This capability has been a game changer for us.
00:15:18.360 So since adopting this pattern, the GitHub application has grown significantly.
00:15:24.240 Last year, while the application grew by 25%, our ViewComponents grew by over 15 times.
00:15:30.180 We’ve learned a lot through this incredible growth.
00:15:37.980 One key insight is how ViewComponents can enforce consistency in our application.
00:15:44.380 Our Design Systems team aims to help developers build consistent UIs.
00:15:50.400 For instance, last summer, one of my colleagues built a ViewComponent for counters used throughout the application.
00:15:58.260 These counters are rendered in about a hundred different places.
00:16:05.520 Let’s examine one of his pull requests. Here, he replaced one counter’s amount with a formatted version.
00:16:12.660 This change led to subtle visual inconsistencies on the page in edge cases.
00:16:20.280 With his update, we pass the raw count to our Primer counter component.
00:16:27.780 Now, the component handles formatting and displaying it consistently.
00:16:35.220 Another advantage of ViewComponents is helping developers write performant code.
00:16:42.660 A common issue encountered is unintentionally querying the database.
00:16:48.900 For example, with permission checks in our views, we might verify whether to show certain elements.
00:16:55.140 These checks can trigger queries if not batched properly ahead of time.
00:17:01.740 To help developers understand how the view code interacts with the database, we redefined the render inline helper.
00:17:08.340 This helper accepts a number of allowed queries, defaulting to zero.
00:17:14.820 When rendering a component, it will fail if it generates more queries than allowed.
00:17:22.740 This approach has fundamentally helped our team understand the side effects of our code.
00:17:29.640 It has also prevented numerous N+1 query issues. Recently, we saved 100 milliseconds per request on the checks page.
00:17:37.620 We've started applying a similar approach to prevent regressions regarding memory allocations.
00:17:44.640 For instance, we specify allowed allocations when refactoring code to avoid increasing memory usage.
00:17:52.560 The same principle applies to performance: we want to ensure our components maintain low memory usage.
00:18:00.960 Another advantage of ViewComponents is their ability to manage complexity, especially in mailers.
00:18:08.280 HTML emails can be challenging to write, often requiring inline HTML.
00:18:15.480 Most of our mailers utilized heavy-handed inline HTML that is hard to maintain.
00:18:23.880 So, when a designer requested adding columns to a mailer, excitement was not the reaction we had.
00:18:30.600 My colleague Mike built mailer-specific components for rows and columns to abstract away complexity.
00:18:38.040 These components enabled reliable column layouts and reduced the need for understanding legacy HTML.
00:18:46.320 Creating a few components has simplified the process of building mailers significantly.
00:18:53.880 If you think about it, it parallels how Active Record operates with SQL.
00:19:01.740 ViewComponents aim to make building UI the default approach, not the exception.
00:19:08.820 Another feature making building UIs easier is slots. Slots allow multiple content blocks to pass to a single component.
00:19:16.320 Here’s an example from our design system: a box component with a header, body, rows, and footer.
00:19:24.840 The HTML for this component can become complex, especially with multiple rows.
00:19:32.520 But when we implement it as a ViewComponent, it simplifies the process.
00:19:41.220 We define named slots for the header, body, and footer, as well as for multiple rows.
00:19:48.960 Utilizing slots, we can pass in specific blocks without worrying about the order.
00:19:56.880 The component implementation can then format the output correctly with the necessary structure.
00:20:03.960 Slots eliminate the burden on developers of managing template integrity.
00:20:11.520 Alongside components, we've also experimented with Storybook, an open-source tool for writing components in isolation.
00:20:19.680 It’s mostly used in React applications but now supports ViewComponents thanks to community contributions.
00:20:27.120 This tool allows us to preview components in action, helping to visualize changes pre-implementation.
00:20:34.320 Over the past summer, we open-sourced our Primer ViewComponents library, which now consists of 40 components.
00:20:41.520 We aren’t alone in open-sourcing our components; the UK government also has several ViewComponents in their design system.
00:20:48.720 Common questions from the community touch on how we're rolling out and ensuring proper usage of components.
00:20:56.160 On the technical side, we create ViewComponents primarily by refactoring existing view code into components.
00:21:03.060 Before ViewComponents, we used a presenter-like pattern called view models.
00:21:11.040 Here’s an example view model using a repository's status to display enabled or disabled.
00:21:19.080 We would pass this object into a template that accesses its values.
00:21:27.000 When rewritten as a ViewComponent, the only significant change was using ViewComponentBase.
00:21:33.240 The tests don't change much; we still perform assertions on the rendered output.
00:21:40.440 However, unlike before, we now need to assert what is presented to users.
00:21:48.000 This shift grants confidence that our view code works well from the customer's perspective.
00:21:56.260 We also write new ViewComponents from scratch when necessary; this generally happens when a complex view has varying states.
00:22:03.660 In these situations, it makes sense to use a ViewComponent for unit testing all those possibilities.
00:22:10.920 Communication has been essential when bringing ViewComponents into our organizational workflow.
00:22:18.500 We focus on documentation for our open-source Primer ViewComponents using YARD.
00:22:25.800 At the top of each component class, we write comments explaining its function and provide ERB examples.
00:22:33.960 These annotations maintain up-to-date docs alongside our code, allowing us to sync both.
00:22:41.560 We also use these YARD annotations to generate our entire documentation site.
00:22:47.520 A rake task parses the project, loads the output into an undocumented object called the registry store.
00:22:55.020 From there, we can render the documentation page.
00:23:02.460 This process helps maintain consistency and accessibility in documentation; it’s consumable through code comments and published files.
00:23:10.740 Also, any examples are executed, catching errors before they become committed.
00:23:18.000 Another way we communicate about ViewComponents is through linters.
00:23:26.880 GitHub uses linters extensively; it’s one of the main mechanisms for managing application scale.
00:23:35.460 For instance, we have a bot that reviews pull requests to encourage the use of ViewComponents.
00:23:41.760 This bot detects outdated methods and provides documentation links for alternatives.
00:23:48.840 We also employ custom rubocop rules, which help discourage using view models in favor of ViewComponents.
00:23:57.180 Linters can recognize class syntax tree nodes, issuing alerts for non-compliance.
00:24:04.680 Given our scale, automation is essential to drive consistent adoption of best practices.
00:24:12.060 Weekly updates summarize project progress and highlight improvements attributed to our approach.
00:24:18.780 These updates help company leadership communicate the value of our work and secure resources.
00:24:25.800 We formed a team of engineers to focus on building and rolling out new ViewComponents this summer.
00:24:32.640 The results were dramatic; we quadrupled the number of component usages in our code base.
00:24:40.440 The momentum continued even after that team concluded its work.
00:24:47.220 Having created a critical mass of examples helped developers copy and paste them into new interfaces.
00:24:54.960 However, we need to ensure the examples used are correct.
00:25:02.520 We achieve this with linters, which help maintain a maximum number of allowed non-component implementations.
00:25:11.040 As the new component is rolled out, we reduce the count of exceptions for legacy implementations.
00:25:18.840 Reporting our progress helps create accountability for using the recommended patterns.
00:25:25.800 For example, when we see 492 usages of a ViewComponent, it indicates our approach is successful.
00:25:32.760 Now, let's discuss lessons from open-sourcing our project.
00:25:39.480 This is my first significant open-source project.
00:25:46.200 We've received a lot of engagement—a hundred developers have contributed code, only a dozen of whom worked at GitHub.
00:25:53.520 This experience has taught me empathy; each interaction holds an opportunity for learning.
00:26:00.960 If someone misunderstands documentation, we can improve it; if an error message fails to clarify an issue, we need to adjust it.
00:26:09.120 People want to contribute; we must enable easy, high-quality contributions.
00:26:16.440 In a growing, complex library, accommodating various Rails versions becomes critical.
00:26:23.520 Using matrix builds helps run the test suite across different Ruby and Rails combinations.
00:26:30.840 This verifies changes work across all versions while maintaining test coverage.
00:26:38.580 Achieving this confidence allows us to accept community contributions safely.
00:26:45.600 Working on this project has highlighted the power of Rails conventions.
00:26:52.800 Aligning the project with Rails conventions makes it intuitive for contributors.
00:26:59.520 For instance, contributors have implemented ViewComponent previews based on Action Mailer previews.
00:27:06.720 Now, it's important to touch on challenges. One issue is the fragmentation in how views are created.
00:27:14.640 We now have two ways of writing views in Rails applications, each with a different approach.
00:27:22.020 I doubt Rails will provide truly native built-in support for this pattern as it currently exists.
00:27:29.700 Yet, there are lessons from this project that could bring improvements to Rails.
00:27:37.680 An example is the experimental gem called Nice Partials, which provides an API similar to ViewComponents.
00:27:46.200 This could be integrated into Rails, easing the transition and improving usability.
00:27:53.220 The long-term focus for this project is enhancing the Rails view layer based on real experience.
00:28:01.560 One glaring issue is the lack of support for caching within this framework.
00:28:09.840 Improving this aspect requires collaboration, possibly from you or others in the community.
00:28:18.360 More broadly, it’s vital to think about innovation in Rails and Ruby.
00:28:25.740 The Innovator's Dilemma outlines this tension between addressing current needs and adopting new technologies.
00:28:32.520 Organizations can do everything right yet still lose market leadership to unexpected competitors.
00:28:40.080 This dilemma speaks to the relevance of our ecosystem.
00:28:47.520 GitHub’s future hinges on Rails and Ruby remaining relevant, as we’ve built immensely upon them.
00:28:55.020 Rewriting our codebase isn't practical; thus, we must innovate to stay current.
00:29:01.800 We must fend for our ecosystem's viability, be proactive, and continuously contribute.
00:29:09.420 All technologies we use are open-source, built by those within our community.
00:29:16.920 We benefit from others' prior contributions but require more involvement from you.
00:29:23.760 We know the inherent shortcomings of these technologies because we’ve worked across countless projects.
00:29:30.600 Identifying pain points is crucial for our companies' survival.
00:29:38.280 Choosing a framework, a technology, or language is pivotal since rewrites are rare.
00:29:45.960 The world will continue to evolve regardless, and it's our responsibility to ensure relevance.
00:29:53.400 Thank you.
00:29:56.820 Thank you, Joel. Yes, it's definitely up to us.
00:30:03.000 That was a beautiful message at the very end. Thank you so much for sharing your story and the story of your components.
00:30:09.360 There was a question in the chat by Marcom asking about the styling of the component.
00:30:15.600 Is it in the global page style, or is there a clever way to load it if it's used in a template?
00:30:22.500 Oh man, that’s a very future-looking question! It’s a problem we're currently examining.
00:30:29.700 We've been deciding how to incorporate successful practices from the React ecosystem.
00:30:36.300 One area of focus is CSS encapsulation and delivering Styles that align well with ViewComponent's architecture.
00:30:43.500 There’s a pull request open in the ViewComponent repository discussing a potential architectural solution to this.
00:30:51.000 My team is poised to take on this task, given we have around 500 kilobytes of custom CSS.
00:30:58.560 We struggle with delivering appropriate Styles at the right places.
00:31:06.000 I might return next year with an update on how this has evolved.
00:31:14.520 There are many people expressing their appreciation for using ViewComponent in production.
00:31:22.320 It seems we are on the right track, and it's exciting to is.
00:31:30.480 I recall the early prototypes, which, despite being hastily produced, surprisingly functioned.
00:31:38.040 Aaron Patterson, Tender Love, and I created the initial prototype together at GitHub.
00:31:45.480 It was an exhilarating experience to see an idea take form and function.
00:31:52.680 And now, it has grown and evolved successfully.
00:31:59.880 Someone asked if we considered using views in an object-oriented manner before going with components.
00:32:08.520 The components originated from an early approach where we had inline templates.
00:32:16.320 It led to complications, particularly with file syntax highlighting.
00:32:24.000 We saw problems with nesting both visually and syntactically.
00:32:31.020 Also, as one of the Ruby core team members noted, inline templates would complicate future Ruby 3 typing work.
00:32:38.580 It quickly became clear that maintaining a singular syntax per file presents a more streamlined experience.
00:32:51.480 While there are extensions to write templates to components, at GitHub we prefer separated implementations.
00:32:57.780 Ultimately, it’s open source, and people can tailor it to their preferences.
00:33:05.280 We still have eight minutes left for Q&A.
00:33:12.300 I have to ask you about other ways you think the Rails view layer could be improved.
00:33:19.920 I'm particularly interested in the modern version of the asset pipeline.
00:33:27.720 Deciding whether to adapt to webpack's architecture has been challenging.
00:33:35.760 It's vital to ensure that traditional benefits remain while also remaining contemporary.
00:33:43.560 The goal is to maintain convention over configuration while accommodating modern demands.
00:33:50.220 It's a challenging endeavor where we strive for balance.
00:33:58.020 I hope that this conversation might kick off further discussions in the community.
00:34:05.160 Thank you, everyone.
00:34:07.560 Thanks once more for being with us, Joel.
00:34:12.600 We look forward to hearing more about your work next year.
00:34:18.300 Enjoy the rest of your day!
00:34:25.020 You too! Thank you!
00:34:26.880 [I am indeed extremely grateful!]
00:34:28.560 This has been a wonderful experience!
00:34:30.900 Returning next year sounds like a great plan! Thank you very much!