Tuesday, April 15, 2014

Be careful with "the Rails way"

The "the Rails way" expression is becoming popular in the Rails community. Depending on the people who use it, it means either something good or something bad. 

(btw, this blog post has nothing to do with a book with a similar title)


This post is about why I think that "the Rails way" is not always so positive. 

Let me start with the DHH ping pong story, which is happening now as it has a good code example to focus on.

The history

The code ping pong with DHH has already started and my submission was chosen by DHH as the first one.
For those of you who are not familiar with the code ping pong action - there was an interesting discussion on HackerNews triggered by the “Rails - the Missing Parts” post.

At some point DHH wrote:

"If this is a poor example, pick a good example. I'll be happy to code ping pong you whatever example you choose.”

The idea was picked up by Marcin "the awesome" Stecki from Netguru, who created http://www.dhh-ping-pong.com/ and announced it at the http://wrocloverb.com/ conference.

As I’m writing a book on this exact topic (how to turn Rails controllers into service objects) I decided to submit my example. I took the code from my recent blog post on refactoring: http://blog.arkency.com/2014/02/rails-refactoring-the-aha-moments/

DHH picked up the example and here we are, having different solutions to the same Rails problem.

This is the actuall Pong page: http://www.dhh-ping-pong.com/pongs/13 (you can vote there).

Why I’m participating in this?

It wasn't an easy decision. Going public with some piece of code is not unusual in the age of open source. Here, however, it's going to be compared. It's going to be pointed out. There's some voting going on. I'm an easy target now ;) 

It's not about voting, though.

The Rails community is huge nowadays. It's not the same small group of people, as it was in 2004-2005. We have hundreds of thousands Rails programmers in the world. Every day, new people are joining our community.

Rails is no longer used only for small apps. 

It's used in enterprise. People rely on Rails codebases to make money for living. I'm sure, that somewhere out there, there is a Rails codebase, on which people lives depend on.

Let's talk about responsibility.

Are we responsible for all Rails codebases out there? For sure, not. But there's a lot we can do to help our community and thus help the people who rely on Rails codebases.

Can we do something about those codebases being better? Not directly. 

A small thing, that we can do is to trigger discussions. It's not for the sake of discussions. It's for the sake of learning. For the sake of improving. 

It's easy to go too abstract with discussions. This is where DHH is totally right. 

Let's focus on the code. 

I'm glad that DHH picked my example. It's based on a real Redmine code. Such code is written everyday by many programmers. The problem is small enough to be presented in one page. It's big enough to show different approaches.

Can my code be better? For sure! My code wasn't meant to be perfect. The main focus of the research and practice for my book is how to let people get out of the messy Rails codebases on a step-by-step basis. You can't risk rewriting the whole part. Every line of code can be hiding some potential user path. You have to make safe steps. 

I believe in gradual improvement. I prefer evolution over revolution in the code.

That's why my example is not perfect. It's just a snapshot from a refactoring session that I took one evening. However, it's good enough to show some concepts. 

It's showing the concept of a Service object. Even, if at the current shape it's using the "hack" of SimpleDelegator, it's worth to have it extracted.

I'm not proud of this code, neither I'm ashamed.

It's hard to discuss code refactorings without taking the time cost into account. It's not impossible to rewrite Redmine to a better code. It's a function of time. 

If you look at the DHH code, the shape of the code (yes, code has a shape!) is better. Overall, the example is shorter than mine. I think not all the cases are covered, but that's not the point. DHH focused on using some of the Rails features to make the code shorter. The code is good. I'd take it over the existing Redmine code, without any doubt (assuming all the paths were covered!).

It's nice to see both the pieces of code, side by side.

We both agree that the existing code was bad

First of all - that's probably most important here - we both agree that the existing code was bad. That's a good starting point.

Where do we differ?

I didn't actually talk to DHH about it. I hope I'm not misinterpreting his intents here.

The main difference seems to be the fact, that I tried to escape the framework as early as possible. I avoided controller filters. I avoided model callbacks. Those are the things that I teach how to get rid of, if possible. DHH went the opposite way, he's using filters, he's using callbacks.

I'm not here to judge which approach is better.

Let me explain my refactorings here. I want to isolate my code from the framework. I didn't go that far, but I also want to isolate the 'logic' from persistence in the next steps (by using the repository pattern). The goal here is to have your logic framework-independent. To be able to run tests quickly, without hitting the database. To be able to split your app into smaller pieces - gems or microservices. To be able to control the whole application easier, this way.

In a way, it's an unusual approach in the Rails world. It's not so unusual if you look at other communities - Java, .Net, Scala, Clojure, Haskell, even PHP (with the fantastic Symfony2 framework).

Wasn't that the reason that we use Rails not to need to escape from it?

Yes and no.

It's a longer story, for another blog post, probably. In short, I believe that Rails is good for the start (as long, as you're not efficient with other approaches yet), however it's bad for a longer run. 

Rails gives you a nice start, very quickly. This usually helps with the costs and the business side of the project. In the longer run, though - you have a much bigger codebase ( think > 100 database tables, if that means anything useful) and you want to split into smaller pieces. The more you're using Rails-specific features, the harder it is to split. It's a hard, ongoing transformation that can take months or years. That's why it's so important to realise it quickly and start sooner.

I've seen many projects that are stagnating with a typical Rails codebase. It's so hard to escape from the Rails monolith at some point.

You can say, that it's about programmers having low skills and that's the problem, not Rails. It's right to some extent. However, when you're stuck with a Rails codebase, you rely on a lot of magic. The Rails framework code is in fact becoming your code. Whatever happens inside, it's your problem now. It's hard to be a good programmer in the legacy Rails environment.

At the beginning the pain is not so visible. It's hard later, when new requirements are coming. The ones, that are not shown on all Rails tutorials. The ones that require you to actually do some domain modelling, to secure the business logic, to hide some data from different roles. This is the place, where Rails is not helping you - it's going into your way. This is the moment, when you realise that mixing logic and persistence is not really the best idea. This is the moment, when your build already takes 20 minutes and you'd actually prefer to add even more tests. This is the moment, when you're better with a modular design instead of the connected design, as Kent Beck rightly points out.



I'm showing a way that makes it possible to deal with bigger Rails codebases in the longer run. I'm not saying this is the only way to stay alive. It's just one way.

DHH and his team are very successful with "the Rails way". Business-wise I can't even compare my "successes" with their huge success. 

Why choose the way I'm suggesting over "the Rails way"? I believe it's easier. It's based more on the overall programming rules, than on relying on some specific Rails features. You can look at the projects created in other communities and apply the lessons in your project. When you rely on Rails, you're in the ActiveRecord-based programming land. A place that lives somewhere between a relational database and OOP. It's a world on its own. You can be successful here, but it's a one-way ticket.


Thursday, January 23, 2014

Refactoring - the human factor

I talked to many people about the concept of refactoring recently. I've noticed a pattern. Not all team members are equally pro-refactoring.

I know how annoying it may be, when you're doing your best to improve the code, you learn how to do it the best way, you try to introduce it and then it's not only not appreciated, but also often rejected. Why is that?

There's plenty of reasons, but most of them come down to the fact that a project is a team work. In a team, we work with other people. We all share the same goal - to let the project succeed. However, we're humans - each of us has a different perception of the goal and the path that leads to this goal.

You may think that it's obvious that a better code will result in the success of the project. In most cases that's true.

You may notice different levels of the refactoring-scepticism.

Do we really need to change the existing code?

If you see such attitude, then one way of dealing with it is going back to the reasons for the refactoring. Is it because you spend a tremendous time on bug fixing? Is it because adding new features takes more and more time? Maybe it's because the app is slow and refactoring can help you extract some parts and later optimize them?

There's never refactoring for the sake of refactoring.

Whatever is the reason, make sure everyone understands it. If there's no understanding, move the discussion one step back. Why is it that your perception of the situation is different? Programmers are smart and logical people. Once you all see facts, metrics and numbers, it's easier to agree on the same solution.

Refactoring takes a lot of time

This is a fair argument. We all care about the time we all spend on the project. Even if it's you doing the refactoring, then everyone is aware of the fact, that this time has a cost.

The best way to deal with this argument is to keep improving refactoring skills. Both yours and your teammates. Examples from the Fowlers' "Refactoring" book are great. If you've done a quick refactoring, maybe it's worth showing to your team on a projector or record a screencast? 

What you want is to have the refactoring cost being almost negligible. If your refactoring changes are fast and safe, then it's quicker to make the change than to discuss it.

I wouldn't refactor this part

I made the mistake of refactoring the part of the code that wasn't really that important to change. It depends of the time spent. It's always good to improve the code everywhere, but what is the price? Does it take you 10 minutes, 1 hour? 10 hours? 10 days? Is it worth it?

Time is our currency, make sure we spend them in the best way.

I would refactor it differently

This problem appears when we have different visions of the refactoring. Let's say you learnt everything you could about DCI and you're sure that's the best direction to go with your project. You envision the contexts, the roles, the objects. Slowly, you keep extracting more code into modules that are later (hopefully) used as roles.

At the same time, your colleague kept studying the concept of microservices. His goal is to split the app into multiple services talking to each other via HTTP/JSON.

Where you see contexts, he sees services.

This represents an architectural difference between both of you.

To be honest, this is a nice problem to have. It means, that people in your team are passionate. They put time into learning new concepts and they are constantly trying to image the app in a different way.

How to deal with it?

I've chosen DCI and microservices as examples, but you could have a much different pair. What matters here is that most of the good architectures are not in fact that much different, however surprising it may sound.

If you want to go DCI and your colleague wants to go microservices, then you have more in common than conflicts. Putting behaviour in the modules, as a step into using them as DCI roles is also a step into the microservices direction (you split the logic in a way that can be used by the microservice, later on). Your main difference is probably the last step - really, that's a nice problem to have :)


One last thing, sometimes you may resort to another option:

Don't call it refactoring

OK, this one is controversial. In some teams, refactoring have negative meaning. It's probably for good reasons. Maybe they've had someone in the team, who didn't deliver value apart from endless refactoring? Try to understand it.

The goal is not to 'do refactoring', the goal is to do better, as a team.

If it doesn't help you, don't call it refactoring. Some teams are totally fine with the idea of The Boy Scout Rule, which means more or less the same as refactoring. Keep improving the code quality, don't call it a refactoring.


Summary

No matter what is the reason of the initial misunderstanding about the refactoring, make sure everyone understands it the same. Most of the times, there's something rational behind the refactoring need.


----

What you just read is an excerpt from my upcoming book: "Rails Refactoring: Service Objects". If you're a Rails programmer and struggle with an existing not-so-pretty Rails code, then you may find it interesting. At the moment, the book is 32 pages, full of code examples and with recipes how to safely, step-by-step improve your Rails controllers, even if you don't have a full test coverage. The beta sale will start very soon. 

If you have examples of ugly Rails controllers, then please, send them to me: andrzejkrzywda@gmail.com.

Sunday, January 5, 2014

Twitter as a geek party

Why do I follow close to 2000 people?
Why do I keep complaining about the Twitter following limit (2000)?
Why am I active on Twitter?
Why did I just unfollow 150 people?




Twitter is an ongoing, very inspiring geek party

I use Twitter in a bit of unusual way. Twitter to me is an ongoing, very inspiring geek party. It’s like a huge, virtual room (Snow Crash anyone?) , which I can enter, whenever I want. I do it every now and then for short moments. I click some links, I see the pics. Conversations are most interesting - I focus on those. What do people talk about? Is it interesting to me? Is it interesting to my work?

Because the topics of their discussions inspire me

I’m mostly connected to the Ruby/Rails community. Why do I follow PHP, Java, .NET people? Because the topics of their discussions inspire me. Why do they keep talking about DDD, when it’s a completely unknown concept in the Ruby community? Is it worth researching it? Can I join the conversation and explain how this problem is solved with Ruby?

I read about 10-20% of the tweets

2000 people is much, but not much if you want to get inspired from many different directions. I hate the Twitter limit - for anti-bot reasons, they put this limit of 2000, probably with the assumption that no one sane, would want to follow so many people. There’s a problem with this assumption. I do want to follow thousands of people, but I don’t want to read all of the tweets. That would be insane. Twitter is not my email - I don’t read everything. I estimate that I read about 10-20% of the tweets. I want to have this mix of people in my timeline. Ruby is a lovely community, but the discussions don’t cover all of the interesting programming topics.

t followings -l --sort=tweeted | head -10 | awk '{print $1}' | xargs t unfollow -i

There’s one thing about the Twitter limit. It gets bigger if I get more followers. In short, I need to have about the same number of followers as the number of people who follow me. I’m not far from that - there’s about 1500 people following me right now, but it’s still not enough. That’s why from time to time I need to clean up the list of people I follow. I unfollow the most silent ones, who didn’t tweet for the last year or so. It doesn’t mean I don’t care about them. If not the limit, I’d be fine. Given, my Twitter usage, though, that makes most sense. I can always follow someone again, if they get more active.

I can’t even describe how much value I get from Twitter

I’m so grateful to the people I follow. I learnt so much, I get inspired so often.

I want to give the value back to my followers. I try to be active, tweet interesting links, engage in good conversations. Teach someone. Actively listen to other people problems. Try helping.

I recommend you to try this approach. Follow more people (use Twitter search to find interesting people). Treat is a geek party. Get inspired. Engage more. Don't read everything.

If you're a programmer, you may enjoy following me - I tweet mostly about programming, JavaScript, Ruby and working from home.

(Photo credits: http://www.flickr.com/photos/romytetue/ )

Saturday, December 28, 2013

How can Rails react to the rise of the JavaScript applications?

The rise of JavaScript applications is tremendous. Every week new JS frameworks appear. Every website UI is now JS-heavy.

How can Rails react to it?

Do we need to worry about our jobs?

History

Let's go back to the history for a while.

Rails was created as a light-weight, but well-structured alternative to create dynamic, db-backed, html websites.

I still own the main Rails book, that was published in 2005: Agile Web Development with Rails. I just checked, there was 558 pages of good content. Only 16 pages were about The Web, V2.0 (this part was written by Thomas Fuchs, not by the main authors - DHH and Dave Thomas). Back then, Rails supported JS via the prototype library. There was no mention about RJS, yet.

Late 2006, I bought another book - Ajax on Rails. I have it in front of me right now. This time, RJS was important already, as they wrote: "Ruby-generated JavaScript (RJS) is the capstone of Ajax in Rails". Before the concept was introduced in the book, all the server did was returning HTML snippets (data) and the JS libraries inserted it into appropriate places. No such thing as view model, data-binding, etc, yet.


Where are we now?

Rails does a really good job of handling the backend part. It's secure, based on conventions, all apps are similar, everybody knows how to work with it.

Look at the frontend part of many Rails apps, though - you don't see the conventions, you don't see the same structure everywhere.

There's this pro-Rails argument, that it's better for a startup to do Rails, because many Rails devs will know what is going on if the project is done the-Rails-way - so, it's easier to scale the team. It's no longer true, though. Yes, the backend part is usually familiar, but the JavaScripts? They're completely different in every Rails app. Often, they're like 50% of the codebase.

Some developers just hack together some jQuery plugins and call it a day.

Some developers go with DHH suggestions and use RJS (UPDATE: or clean JS returned from the server) (to be honest I have never seen this approach in a Rails app, but I'm sure someone followed DHH here).

The new trend is to use JS frameworks, like Ember.js or Angular.js, which are opinionated and feel more aligned to the philosophy of Rails (conventions, magic, implicit features).

Other developers (me included) want to control the JavaScript app and don't use any framework, relying on self-imposed architectures like http://hexagonaljs.com/.

How can Rails react?

There are some possible ways of reacting. I'm trying to be neutral here, although obviously I have an opinion on that.

1. We can leave it as it is, with [R]JS being recommended by the leader

From my observations, the [R]JS recommendation gets ignored mostly. To be fair, none of the leaders is actively discouraging anyone to use some proper JS frameworks. It's just not the main focus.

This leaves the community disconnected from the leader (which may not be a bad thing). I've met many people who are worried for the future of Rails. They're not sure if Rails is a good technology to invest their time. For such people it may mean that in the longer run, they'll prefer to focus their education on the JS part more than on the Rails. We already see the increasing number of jobs ads requiring Angular or Ember.

This way, we'll see the trend started with rails-api growing in popularity.

2. Rails can adopt/recommend one of the JS frameworks.

It can be Angular or Ember. The first one has a huge growing trend recently. Ember is led by well-respected people from the Rails community (Yehuda). It's smaller overall but quite popular in the Rails world already.

We've seen a similar situation in the history of Rails, when Yehuda created Merb and then made it to Rails (oversimplifying a bit). Can the same happen with Ember? It's very likely.

What about Angular which is becoming the default JS framework? Can Rails recommend it? There's nothing in Rails that makes it hard to develop with Angular. But Angular is not the default choice, yet. DHH made some bold moves in the past, like making CoffeeScript on by default (thank you!). Can the same happen to Angular?

3. Rails will encourage JS frameworks but stays JS-framework-agnostic.

This is more or less what is happening already in the community. People use Rails together with many of the existing JS frameworks, with success.

4. All of the above

We can see DHH keep recommending [R]JS. The Rails core will make Ember the default choice, but easy to disable it. The community will keep using Rails together with everything.

The future

What is going to happen? I honestly don't know. Rails is doing fine-enough. It doesn't need to react in any way. We need to remember that it's not only about purely rational, technological choice. Rails was always famous for its marketing. We can see some unexpected moves, like coming up with its own JS framework.

What would I prefer?

Personally, the current situation is fine for me. I ignore the [R]JS way of creating the Rails apps. I'm allowed to create the JavaScript apps the way I want. Rails is good for API. I'm fine with any choice.

However, as I said, it's not only about rational choices, it's about the emotions. Do we want it or not, the Rails community is huge nowadays with new people coming every day.

If my main goal was to keep Rails hot for the new people, then I'd suggest choosing Angular as the framework that is on by default in Rails. That would bring a lot of love to the community. Angular is loved they way Rails used to be loved.  I personally don't really like the Angular way, but this choice will be good/easy for the new people for whom it's better to follow choices made by others.

In the meantime, other backend communities keep improving. Did you see PHP and Symphony2? It's a framework which is architecturally ahead of Rails (a topic for another blog post, probably). Did you notice how popular Scala is becoming?

Should we care about the future of Rails? Is it more pragmatic to be backend-independent and start learning more about other backend choices? Should we go the microservices way and have the app implemented in several backend technologies at the same time?

Many questions, lots of guessing :)

If you liked this blog post, you will enjoy following me on Twitter.

UPDATE: I changed RJS to [R]JS in some places. It's not really RJS that is recommended by DHH, but SJR - Server JavaScript Responses - see http://37signals.com/svn/posts/3697-server-generated-javascript-responses

Sunday, December 22, 2013

Decentralise id generation

It seems to be a common practice nowadays to rely on the database-generated, incremental id.

In one of our projects, we let the client-side (JS) generate the id (using guid/uuid). It leads to interesting consequences. We no longer need to send the form data to the backend immediately. If we want, we can create the object on the client-side, give it a guid, keep editing it and then send it back to the server, with the guid. The server stores the guid and uses it for identification. The same can happen at the same time from another Ruby client that connects to the same API.

This is how an example guid looks like:

f81d4fae-7dec-11d0-a765-00a0c91e6bf6


"A UUID is 128 bits long, and can guarantee uniqueness across space and time."

RFC: http://www.rfc-archive.org/getrfc.php?rfc=4122

"A UUID is an identifier that is unique across both space and time, with respect to the space of all UUIDs. Since a UUID is a fixed size and contains a time field, it is possible for values to rollover (around A.D. 3400, depending on the specific algorithm used)."

"Unless you're accepting IDs on, say, an Internet-wide scale, or with an untrusted environment where malicious individuals might be able to do something bad in the case of an ID collision, it's just not something you should worry about."

My opinion on UUIDs

For years, I have been thinking that centralised id generation is the natural way. Seems obvious. After I learnt mote about UUID, I start seeing more and more good things about it. It allows for less coupling between components/services.  You no longer need to 'ask' for the id. In case of JavaScript frontends it solves the problem of whether to block the UI, when we create a new resource.

The area, that I haven't researched much is having distributed database which you sync between the services. From what I know, it's already possible with http://www.datomic.com/.

Ruby 

Ruby has a built-in method:

http://www.ruby-doc.org/stdlib-1.9.3/libdoc/securerandom/rdoc/SecureRandom.html#method-c-uuid

p SecureRandom.uuid
# "2d931510-d99f-494a-8c67-87feb05e1594”

JavaScript

JS library
https://github.com/pnegri/uuid-js

var uuid4 = UUID.create();
console.log(uuid4.toString());
// Prints: 896b677f-fb14-11e0-b14d-d11ca798dbac


Python

>>> import uuid
>>> # make a UUID based on the host ID and current time
>>> uuid.uuid1()

UUID('a8098c1a-f86e-11da-bd1a-00112444be1e’)


Java

UUID uuid = UUID.randomUUID();



Also worth reading: http://stackoverflow.com/questions/703035/when-are-you-truly-forced-to-use-uuid-as-part-of-the-design/786541#786541

Saturday, December 21, 2013

The Four Architectures that will inspire your programming

This is the Big 4. The architectures, that may help your work. They may influence the way you think about programming.

1. The Hexagonal Architecture

(also known as the Ports and Adapters)

Originally described by Alistair Cockburn in http://alistair.cockburn.us/Hexagonal+architecture.
Enhanced and popularised by Steve Freeman and Nat Pryce, thanks to their book: http://www.growing-object-oriented-software.com/

2. Clean Architecture

Originally described by Ivar Jacobson, but popularised by Uncle Bob: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

3. DDD/CQRS

DDD: Domain-Driven Design
CQRS: Command Query Responsibility Segregation

Two separate concepts, but together create quite a unique architecture.
DDD is originally invented by Eric Evans. CQRS is often popularised by the work of Greg Young.

4. DCI

DCI: Data Context Interaction

James Coplien, Trygve Reenskaug
Desribed in James' book: http://www.leansoftwarearchitecture.com/ and here: http://www.artima.com/articles/dci_vision.html


What I think about them

I don't treat them as competitors. Learning the concepts behind them (still in progress) inspired me to bring some new ideas to our projects. Usually, they're not all or nothing.

The most mind-blowing architecture is definitely DCI. This is the future of programming. The vision of objects being different things in different contexts, while still keeping its identity is fantastic. Unfortunately, DCI is also the hardest one to use in day-to-day practice. Some of the concepts required (objects with roles) are hard to achieve in most popular languages.

The most practical architecture is possibly DDD/CQRS. There is a lot of example projects in many different languages. I love the pragmatic approach of splitting the system into Commands and Queries. At first, I couldn't get the point, but after more reading I see the beauty of it. I sometimes laugh that DDD could stand for (data) Duplication-Driven Design. It opened my eyes to the idea, that we can have multiple subsystems, each with its own storage. Some data will be duplicated this way, but it's often not a problem. The data is eventually consistent.

Another nice thing about DDD is the idea of Bounded Contexts. It's a terrible name, but a really useful concept of a module that encapsulates one little world of your project. Usually, you have one root object in each Bounded Context, which is called Aggregate. The same 'object' can exist in different BC, but will have a different name. Its identity will be kept via a unique id.

CQRS brings the concept of Commands being the most complex parts of your app, while Queries are usually very simple and don't require many layers.

What I like about the Clean Architecture is its focus on clear dependencies and on boundaries. Boundaries should be kept outside of your application. The communication between boundaries should happen via Data Transfer Objects. In the middle there's the Interactor, which represent a UseCase.

Last, but not least, we've got the Hexagonal Architecture. This is what inspired us mostly to create the JavaScript non-framework called http://hexagonaljs.com/. It's so easy to extract GuiAdapter and StorageAdapter, leaving the middle hex boundary-unaware.

HexagonalJS is a result of inspiration from all of the above architectures. We took the UseCase/Context part from the DCI architecture with a little bit of the Clean Architecture. The idea of adapters is taken from the Hexagonal Architecture. The middle hex is often implemented using the building blocks taken from DDD. Our unique addition to this setup is a little bit of Aspect Oriented Programming.

Often, when I'm in doubt how to approach a new project, I'm trying to stand far from the Upfront Design. However, it doesn't hurt if I imagine the project in each of the architectures. This gives me new ideas about the domain I'm implementing.


If you liked this blog post, you will enjoy following me on Twitter.


Friday, December 20, 2013

Turn a Rails controller into a Single Page Application


Single Page Apps are becoming more popular. When you see them in practice (GMail, Twitter, Facebook), it's quite cool. Then you look at your current project and you see how impossible it is to make it a Single Page App. Who's going to pay for that? It sounds like months of work, just replacing the whole existing functionality.

The thing is, it doesn't need to be the whole project at once. It's not all or nothing. You can make multiple small SPAs.

Where to start?

Look at your current Rails views/controller. Is there a clear widget, like a search bar, that could be extracted? That's a good candidate.

There's also another approach. Usually when you have a typical CRUD controller, it's always the same group of views. There's a list of things, that you can see, edit, update, add new items, etc.

Such controller is a good candidate for a SPA.

You end up with one view (index), which loads the JS. After the JavaScripts are initialised, an AJAX GET request is made to /index.json. This retrieves all the data for the list. Apart from that you need an API endpoint for creating, updating and deleting. Note that you don't need an endpoint for new/edit. They become JavaScript views, but they don't need to exist on the server-side. 

You turn the existing Rails views into handlebars templates (or whatever that renders the HTML client-side). They get rendered at appropriate moments by the JavaScript code.

If you prefer, you can use a framework for that. You can also do it on your own, as it's very easy. We usually go the hexagonaljs way - manual, with a nice structure and typical adapters: serverSide and guiAdapter. 

What does it give you?
  • Single Page Apps are architecturally better solutions than Rails views
    • it's easier to test
    • once you learn it, it's quite easy to write
    • there's strong decoupling between your frontend and the backend
    • the backend is simpler
    • the resulting SPA has less 'features' than a Rails view
      • by default, no URL for each 'view', just for the main one
        • good enough for most cases
      • for SEO you need to do additional work on the backend
        • not always needed
It doesn't need to be all or nothing

You can test the water by choosing some parts of your project and turn them into JavaScript apps. We're in the process of doing that in a large Rails project - I think, we're now with about 15 small Single Page Apps. We keep adding new features, it doesn't slow us down. Thanks to the faster build (it's easier to test decoupled components rather than a monolith), we're actually saving time.