Are you sure?
Decorators decorate your class with new set of functionality.
What are your decorators doing? Adding a few rendering specific methods to a class to help with rendering? Perhaps you should consider Presenters. But better: how will it scale, can it be grouped, will it really add the simplification. Be wary of too quick branching off functionality to decorators. Most cases I've seen them were overly architectured, and they didn't bring much value.
One might consider using Concerns or mixins as an alternative. The disadvantage here is that your main object gets more public methods, but I consider it as a feature after having experienced too much potentially reusable functionality grouped arbitrarily away in other presenter / decorator classes.
So I wrote a few short articles on when to use FormObjects and Jobs and ServiceObjects. The question is of course "it depends", but the leading principle I have is keep it simple. That being said, for inspiration, some suggestion for different layers to manage the application complexity from Vladimir Dementyev's talk on Railsconf:
Whenever your model gets too heavy?
The easiest way to clean up your classes might be to create smaller, more concise methods. The next easiest way of tiding up your models is moving stuff to modules (whether they are 'Concerns' or not). Modules can then be included in the final classes. It will lead to a crowded list of methods exposed on these classes, for which alternative solutions exist (Presenters, Decorators), but if you shield off private methods nicely and have a consistent way of naming things, I wouldn't be too concerned about that. Note that having many modules used in only a single class might be a code smell: perhaps you're trying to do too much with that single class.
When you're using Rails, you can make use of Concerns. They offer a few advantages over traditional modules, so use it whenever you're bothering recreating the same behaviour using plain old ruby Modules. I prefer consistency, so if you've adopted Concerns, use con…
When necessary.
It depends. By default I would advise against them; not creating Form objects to receive and validate data that could be validated by the Model directly. Even when you have a few nested attributes that belong to the main model modified, I would advise against Form objects. Keep It Simple.
But… sometimes you have more complex forms that don't fit the database-mirroring ActiveRecord model as nicely.
Always.
When you are able to do stuff async (not blocking the web-request), make it async. It will also reduce the need for a category of Service-objects. Worker or Job objects can often be called inline if desired.
Sidenote: I personally prefer the "Job" object name, a Job that needs to be performed. Worker is a name that was popularised by Sidekiq, but Sidekiq moved to Jobs as well.
Never.
There is of course never an absolute answer to stuff but if you are running it in a background job anyway have you considered directly writing it in a Worker or Job-object? Note that you can always run jobs async when needed.
My main objection against service objects is that all too often they are ill defined as a category. So while having fat controllers or fat models may be a bad thing, just creating a bunch of somewhat arbitrary 'Services' is not making the code more manageable.
When considering adding a 'services' directory to your app, try to think of what class of problems you want to tackle. And when in doubt, just keep messing around with the somewhat fatter models & controllers.
Ever had the problem that you reuse the same project for a managemable number of clients? Too few to store branding materials in a database, but more than one making it hard to keep separate branches in sync?
Introducing BrandingRepo (for Rails)
The idea is simple: create a configuration file with those files that are specific to different brands/customers and store their mods in a different repository. Repository is quite a big word here: we simply create a config/brands
folder in your current branch where you can push and pull your brand specific adjustments from. All managed in the same git repository.
What it is not:
Add this …
I'm still a big fan of Ruby on Rails. No other framework has ever made me as productive. And it is no a secret that it makes quite some other product companies very successful. Think of Shopify, Github, Basecamp, Hey, and others.
But if you'd look at at the list of most popular languages, the top 10 doesn't feature ruby anymore.
In their 2020 survey on most popular technologies, StackOverflow writes:
> Additionally, Ruby, once in the top 10 of this list as recently as 2017, has declined, being surpassed by newer, trendier technologies such as Go and Kotlin.
Also if you look at Google trends, ruby has always been negligible when compared to Python or PHP or Javascript, [the trend is downward for the ruby package manager](https://trends.google.nl/trends/explor…
I recently shared an overview article about Stubbing External Services in Rails. I found it when looking for the best way to stub a pletora of services in a microservices environment. Sure, docker (or whatever) everything and run it locally / in your test suite. But unless you've plenty of disk- and memory space, this isn't always a viable option. The alternative: simulate the service. Mock or stub the endpoint.
The go to gems are Webmock, which catches request and allows you to define the responses explicitly and VCR, which allows you to record responses, and play back.
VCR is quite cool, but as it is a recorder of earlier responses, there may be a lot of noise to dig trough when trying to make the responses a bit more generic (dealing with random token requests and what else)
For testing I pers…
A quick note, because I was using the wrong search terms. If you want to share e.g. the current user of an app with a model you can now (since Rails 5.2) use a model inheriting from ActiveSupport::CurrentAttributes. Before you were required to pass this current user explicitly or find another way to access state.
Note that this can either be a good thing or a bad thing (tl;dr: thread-local global state makes apps unpredictable)
And even the docs warn against abusing this feature. Powerful tools can come with dangerous consequences :) Global variables are immensely powerful. Use with care. I'm not even sure if I'm going down this path…
There are a lot of things that I don't understand. One of these things is how memory management really works. Memory management is hard, and even though I use languages that do garbage collecting by themselves, long running ruby apps seem to run out of memory after n number of days. Even the pro’s find it quite hard. While I previously resetted the failing app every now and then, I was triggered by Mike Perham’s (creator of Sidekiq) post: “Taming Rails memory bloat”.
When you start searching for the memory bloat problem, you'll find several directions. The easiest is changing a global variable which changes the number of “arena’s” where memory allocation takes place (note: I’m in no position to explain all this, please follow the references). The fanciest, however, seems to be changing the memory allocator from glibc's default 'malloc' to jemalloc. See for example [this](https://www.speedshop.co/2017/12/04/malloc…
Prometheus is a statistics collecting tool that originated from SoundCloud. Designed to be used in high performance environments, it is build to be blazingly fast. Hence, the client typically is expected to be blazingly fast as well, gathering and presenting data within nanoseconds. For Ruby on Rails applications however this has lead to an unresolved issue with the Prometheus ruby-client when the same application is forked (typical for Puma, Passenger and other popular ruby-servers). The Prometheus client collects data within its own fork before serving it to the exporter endpoint. This can or cannot be a problem. When you measuring response times, running averages from a random fork may be good enough. However, when you're also counting data over time you're having separate counters in …
Still (2013) a great talk by Sandy Metz on testing, and how to do it right, without getting too theoretical. While this talk is on ruby, and it uses a Rails framework for testing, it really is applicable to any other language (only the syntax will probably be a wee bit shittier ;))
Watch Rails Conf 2013 The Magic Tricks of Testing by Sandi Metz on YouTube
(and while unit-testing is between brackets, in general, being a minimalist when writing code really is a good idea)
Webpacker is still opt-in for new Rails projects. But this might change. The JavaScript ecosystem is moving fast and new JavaScript frameworks are pushing customer’s expectations to higher levels. To use these frameworks with your Rails app, you had a few options:
npm
or yarn
into the asset pipeline yourselfI have been using rails-assets.org the past few years to keep my JavaScript dependencies up to date. It thought it was smart solution; instead of requiring individual developers to maintain Gem-wrappers, Gem wrappers are created on the fly by RailsAssets.org. It was smart and light weight on the developers side and worked perfectly with the Rails' Asset p…
It may not be the fastest programming language, nor is it the most popular language when it comes to the numbers game, but how can you not fall in love with:
10.times { print "Hello!" }
(instead of something like for(var i=0; i<10; i++){ console.log("Hello!"); }
)
Do things with sets like:
["a", "b", "c"] & ["b", "c", "d"] ## gives you ["b", "c"]
[1,2,3] + [4,5] ## gives you [1,2,3,4,5]
["a", "b", "c"] - ["b", "c", "d"] ## gives you ["a"]
Or (with a little (opinions differ on this one ;)) help of Rails):
10.days.ago
That offers you exactly what you would think it would return: the date of 10 days ago.
And no ;
's, only brackets when absolutely needed, everything is an object…
Yes, it's actually a language a human might understand, and still: it is pretty powerful, powering some of the most popular sites on the web, like AirBnB, Shopify, Basecamp (they're the creators of Ruby on Rails), Github, Kickstarter, Twitch, Strava and man…
Dit artikel van murblog van Maarten Brouwers (murb) is in licentie gegeven volgens een Creative Commons Naamsvermelding 3.0 Nederland licentie .