<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Rodrigo Rosenfeld Rosas</title><description>Rodrigo Rosenfeld Rosas — blog</description><link>https://rosenfeld.page/</link><language>en-us</language><item><title>Seamless Postgres Indexing in Rails: The Case for Delayed Migrations</title><link>https://rosenfeld.page/articles/ruby-rails/2026_02_27_seamless_postgres_indexing_in_rails_the_case_for_delayed_migrations/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2026_02_27_seamless_postgres_indexing_in_rails_the_case_for_delayed_migrations/</guid><pubDate>Fri, 27 Feb 2026 16:18:00 GMT</pubDate><content:encoded>&lt;p&gt;Adding an index to an existing table column might seem straightforward.
However, PostgreSQL requires a &lt;em&gt;SHARE&lt;/em&gt; lock to create a standard index.
This mode conflicts with common write operations like &lt;em&gt;INSERT&lt;/em&gt;, &lt;em&gt;UPDATE&lt;/em&gt;,
and &lt;em&gt;DELETE&lt;/em&gt;, which use the &lt;em&gt;ROW EXCLUSIVE&lt;/em&gt; lock mode. These articles
explain the issue in depth:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bytebase.com/blog/postgres-schema-migration-without-downtime/&quot;&gt;Postgres Schema Migration without Downtime Best Practice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bytebase.com/blog/postgres-create-index-concurrently/&quot;&gt;How to Use Postgres CREATE INDEX CONCURRENTLY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Creating the index concurrently allows those write operations to happen
while the index is being created, which can take quite a few minutes in
huge tables. If those operations were blocked during that time the application
would experience many request timeouts and the application would become
unresponsive until the index creation is completed.&lt;/p&gt;
&lt;p&gt;I am currently working on a Rails application hosted on Heroku.
This application makes use of the &lt;a href=&quot;https://github.com/ankane/strong_migrations&quot;&gt;strong_migrations&lt;/a&gt; gem,
which &lt;a href=&quot;https://github.com/ankane/strong_migrations/blob/master/lib/generators/strong_migrations/templates/initializer.rb.tt#L5&quot;&gt;sets a lock timeout of 10 seconds by default&lt;/a&gt;.
Under heavy load, it can take a long time to acquire the
lock necessary to complete index creation.&lt;/p&gt;
&lt;p&gt;When that happens the whole deployment fails because the &lt;em&gt;db:migrate&lt;/em&gt; task
failed, leaving the created index in an invalid state. It gets worse because
indices can&amp;#39;t be created concurrently in a transaction, which means the
migration must call &lt;em&gt;disable_ddl_transaction!&lt;/em&gt;. Any changes already made to
the database are not rolled back if the migration fails.&lt;/p&gt;
&lt;p&gt;Even if the only operation in the migration is the index creation, the
migration can&amp;#39;t be retried until we remove the invalid index first if
the migration specifies the index name.&lt;/p&gt;
&lt;h2&gt;Other issues caused by concurrent index creation&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;strong_migrations&lt;/em&gt; gem can automatically get rid of invalid indices,
through the &lt;code&gt;StrongMigrations.remove_invalid_indexes = true&lt;/code&gt;
&lt;a href=&quot;https://github.com/ankane/strong_migrations/blob/master/lib/generators/strong_migrations/templates/initializer.rb.tt#L24&quot;&gt;setting&lt;/a&gt;.
That fixes part of the problem with retrying failed migrations.
Since indices can&amp;#39;t be created concurrently within a transaction, we
should create indices in dedicated migrations.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s no guarantee we&amp;#39;ll get the lock before the lock timeout. If the
migration fails, the whole deployment will fail and it will prevent us
from deploying other changes as well until the migrations are applied
successfully. We want to prevent the situation where a single
index creation migration could block all deployments until off hours
when the application is less busy and the lock can be acquired within
10 seconds.&lt;/p&gt;
&lt;h2&gt;Delayed migrations to the rescue&lt;/h2&gt;
&lt;p&gt;In order to fix those issues we decided to handle index creations
in delayed migrations. They work just like regular migrations
except that they are not executed during the release phase. We run
those migrations after a successful deployment instead. These
migrations are stored in a separate location and new Rake tasks
have been created to run them.&lt;/p&gt;
&lt;p&gt;It changes the way we implement some changes too. Instead of deploying
database changes alongside with code changes we first prepare the
database before deploying the new code. Once the indices are
created we can merge the new code using the index.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve implemented a robust set of Rake tasks to handle this automated process.
Here is the implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# frozen_string_literal: true

namespace :delayed_migrations do
  helper = Module.new do
    module_function

    def with_delayed_migrations(&amp;amp;block)
      ActiveRecord::Base.connection.execute(&amp;quot;SET lock_timeout = &amp;#39;1h&amp;#39;&amp;quot;)
      pool = ActiveRecord::Base.connection_pool
      path = Rails.configuration.app.delayed_migrations_path
      context = ActiveRecord::MigrationContext.new(
        path, pool.schema_migration, pool.internal_metadata
      )
      block.call(context)
      Rake::Task[&amp;quot;db:schema:dump&amp;quot;].invoke if ActiveRecord.dump_schema_after_migration
    end
  end

  desc &amp;quot;Run all pending delayed migrations&amp;quot;
  task run: :environment do
    helper.with_delayed_migrations(&amp;amp;:migrate)
  end

  desc &amp;quot;Run a specific delayed migration (e.g. rails delayed_migrations:up[20231027123456])&amp;quot;
  task :up, [:version] =&amp;gt; :environment do |_, args|
    version = args[:version]&amp;amp;.to_i
    raise &amp;quot;Version is required. Usage: rails delayed_migrations:up[VERSION]&amp;quot; if version.nil?

    helper.with_delayed_migrations { it.run(:up, version) }
  end

  desc &amp;quot;Rollback a specific delayed migration (e.g. rails delayed_migrations:down[20231027123456])&amp;quot;
  task :down, [:version] =&amp;gt; :environment do |_, args|
    version = args[:version]&amp;amp;.to_i
    raise &amp;quot;Version is required. Usage: rails delayed_migrations:down[VERSION]&amp;quot; if version.nil?

    helper.with_delayed_migrations { it.run(:down, version) }
  end

  desc &amp;quot;Rollback the last delayed migration&amp;quot;
  task rollback: :environment do
    helper.with_delayed_migrations(&amp;amp;:rollback)
  end

  task extend_migrate_status: :environment do
    next unless Rake.application.top_level_tasks == [&amp;quot;db:migrate:status&amp;quot;]

    migrations_path = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
    delayed_path = Rails.configuration.app.delayed_migrations_path
    migrations_path &amp;lt;&amp;lt; delayed_path if migrations_path.exclude?(delayed_path)
  end
  Rake::Task[&amp;quot;db:migrate:status&amp;quot;].enhance([&amp;quot;delayed_migrations:extend_migrate_status&amp;quot;])
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s now a matter of generating a new migration, adding the index creation logic,
moving the migration to &lt;code&gt;db/delayed_migrations&lt;/code&gt;, and running
&lt;code&gt;bin/rails delayed_migrations:run&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can run this command through &lt;em&gt;heroku run bash&lt;/em&gt; or using a background job
scheduled after each release, for example. If the command times out it&amp;#39;s
retried later on. Once it&amp;#39;s run successfully we can proceed with the code
changes that use the new index.&lt;/p&gt;
&lt;h2&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;This is a very common problem with applications running in production
that I&amp;#39;m surprised I don&amp;#39;t see an out-of-the-box solution from Rails
or any other gem. Maybe I&amp;#39;m missing something so please let me know
in the article comments if there&amp;#39;s a built-in solution to this problem
that I&amp;#39;m not aware of.&lt;/p&gt;
</content:encoded></item><item><title>Upgrading 200 GB Postgres within 10 minutes in Heroku</title><link>https://rosenfeld.page/articles/2025_11_16_upgrading_200_gb_postgres_within_10_minutes_in_heroku/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2025_11_16_upgrading_200_gb_postgres_within_10_minutes_in_heroku/</guid><pubDate>Sun, 16 Nov 2025 13:37:00 GMT</pubDate><content:encoded>&lt;p&gt;I joined a new project 4 months ago. While investigating a slow query I noticed
that even after creating a new &lt;a href=&quot;https://www.postgresql.org/docs/current/indexes-index-only-scans.html&quot;&gt;covering index&lt;/a&gt;
the query planner would refuse to use it. We were running Postgres 15 and I
decided to try Postgres 17 and confirmed it would use the covering index as
expected which significantly improved the query performance.&lt;/p&gt;
&lt;h2&gt;The follower database upgrade issue&lt;/h2&gt;
&lt;p&gt;Next step was to push for the Postgres 15 to 17 upgrade, which seemed pretty
straightforward according to this &lt;a href=&quot;https://www.heroku.com/blog/heroku-postgres-upgrade-guide-simplify-move-version-17/&quot;&gt;post from Heroku&lt;/a&gt;.
So I gave it a try last Sunday in our staging database and noticed 2 things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The sign-in page downtime was about 3 minutes.&lt;/li&gt;
&lt;li&gt;Other parts of the application were down for much longer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After inspecting the logs I noticed that parts of our application required
our follower database to be available for increasing our read throughput,
which is a common practice supported by Heroku. What that article from Heroku
fails to clearly explain is that the &lt;em&gt;prepare&lt;/em&gt; phase is only spawned for the leader
database. That&amp;#39;s why the sign-in page would be down for only 3 minutes
but it took 20-30 minutes for our staging environment to be available again.&lt;/p&gt;
&lt;p&gt;Once the leader upgrade is completed, the followers upgrade process start,
but the follower becomes immediately unavailable once the leader upgrade
completed until the follower upgrade completes. Our staging database is
pretty small, but our production one is almost 200 GB, so I anticipated
it could be down for one hour or more until the follower database
upgrade was complete.&lt;/p&gt;
&lt;p&gt;During all that time the application would fail with 500 due to being
unable to connect to the follower read-only database.&lt;/p&gt;
&lt;h2&gt;The plan for upgrading the production database&lt;/h2&gt;
&lt;p&gt;Once well understood how the Postgres upgrade works in Heroku, it was time
to update the upgrade plan to take the follower into account. We have
significantly less traffic on weekends so I upgraded the production database
over this weekend using the following plan successfully:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Yesterday (Saturday) I ran the &lt;code&gt;heroku pg:upgrade:prepare&lt;/code&gt; to start the
prepare phase. This spawns a new follower PG 17 database and schedules the
upgrade to happen automatically in our next maintenance window, which would
be next Tuesday.&lt;/li&gt;
&lt;li&gt;Then I pointed our read-only environment variable to our leader so that
the app would no longer use our follower database until the upgrade was
completed.&lt;/li&gt;
&lt;li&gt;Today (Sunday) I paused all background jobs queues, switched on the
maintenance mode on for the application and ran the &lt;code&gt;heroku pg:upgrade:run&lt;/code&gt;
command and watched the progress with &lt;code&gt;heroku pg:upgrade:wait&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;9 minutes later and the new database was upgraded and available, so
I turned off the maintenance mode and after confirming the live app
was working fine I unpaused all background job queues.&lt;/li&gt;
&lt;li&gt;I watched &lt;code&gt;heroku pg:upgrade:wait&lt;/code&gt; while the follower database was
being upgraded. Once the application completed about an hour later I
restored the read-only database URI to point to the follower again and
monitored it for a few minutes to make sure the application was working fine.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I used to host my page on Heroku when I first created it and only moved
from Heroku when the free plan wasn&amp;#39;t available anymore. But I never really
dug in Heroku&amp;#39;s infrastructure before like I had to do once I joined this project.&lt;/p&gt;
&lt;p&gt;I must say I&amp;#39;m positively surprised with the experience of using Heroku for
hosting a big project like this one, especially with the experience of
upgrading Postgres. I just feel their articles failed to better explain how
the upgrade process works, especially regarding followers upgrade and
timing. This article intends to help people upgrading the leader and their
followers to Postgres 17 seamlessly on Heroku until they update their articles.&lt;/p&gt;
&lt;p&gt;Heroku positively surprised me in many other areas, including monitoring
and metrics. However I miss more dyno types from their plans. They offer
a 1 GB RAM dyno for $ 50 / month, then 2.5 GB for $ 250 / month (5 times
the price of the previous tier) and the next tier would allow for
30 GB at $ 500 / month. Why don&amp;#39;t we see plans with 4 or 8 GB for
$ 150/200 monthly, for example? Anyway, it is what it is and we have to
adapt if we want to stay in the platform, but overall it&amp;#39;s a great
platform for companies with a small team, like ours.&lt;/p&gt;
&lt;p&gt;Well, this client was acquired by a bigger company a few weeks ago, so
they might decide to switch to some Kubernetes setup in the future to
save some money if they already have some operations team in place.
While it doesn&amp;#39;t happen I&amp;#39;m going to enjoy Heroku&amp;#39;s infrastructure and
great tools, including the automated Postgres upgrade.&lt;/p&gt;
&lt;p&gt;And yes, we&amp;#39;re no longer getting request timeout errors due to the
bad query plan from PG 15. After upgrading to PG 17 those request timeout
errors were gone and the queries now complete within a few milliseconds.
I highly recommend upgrading to newer Postgres versions. PG 18 isn&amp;#39;t
available on Heroku yet, but I&amp;#39;ll keep an eye on it.&lt;/p&gt;
</content:encoded></item><item><title>Why is your Rails app boot slow?</title><link>https://rosenfeld.page/articles/ruby-rails/2024_10_25_why_is_your_rails_app_boot_slow/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2024_10_25_why_is_your_rails_app_boot_slow/</guid><pubDate>Fri, 25 Oct 2024 20:35:00 GMT</pubDate><content:encoded>&lt;p&gt;In my &lt;a href=&quot;2024_10_25_creating_web_app_monoliths_that_boot_instantly_with_ruby&quot;&gt;previous article&lt;/a&gt;
we explored how we can build huge web app monoliths with Ruby that can complete simple
request tests in under a second. In this article we&amp;#39;ll focus on Rails apps. We&amp;#39;ll
identify what causes a big app to take a long time to boot and run simple tests and what
we can do to improve the situation.&lt;/p&gt;
&lt;h1&gt;How fast can Rails boot?&lt;/h1&gt;
&lt;p&gt;Let&amp;#39;s start by investigating how fast we can expect a Rails app to boot. Let&amp;#39;s check
against a minimal Rails app first:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;bundler/inline&amp;#39;

ENV[&amp;quot;BOOTSNAP_CACHE_DIR&amp;quot;] ||= &amp;quot;tmp/cache&amp;quot;

gemfile do
  gem &amp;#39;bootsnap&amp;#39;, require: &amp;#39;bootsnap/setup&amp;#39;
  gem &amp;#39;minitest&amp;#39;, require: &amp;#39;minitest/autorun&amp;#39;
  gem &amp;#39;ostruct&amp;#39;, require: false
  gem &amp;#39;rack-test&amp;#39;, require: &amp;#39;rack/test&amp;#39;
  gem &amp;#39;railties&amp;#39;, require: &amp;#39;rails&amp;#39;
  gem &amp;#39;actionpack&amp;#39;, require: &amp;#39;action_controller/railtie&amp;#39;
end

class MinimalApp &amp;lt; Rails::Application
  config.root = __dir__
  config.eager_load = false
  config.hosts &amp;lt;&amp;lt; &amp;quot;example.org&amp;quot;
end

MinimalApp.initialize!

MinimalApp.routes.draw do
  get &amp;#39;up&amp;#39; =&amp;gt; &amp;#39;rails/health#show&amp;#39;
end

describe &amp;quot;/up&amp;quot; do
  include Rack::Test::Methods
  def app = MinimalApp

  it &amp;quot;responds with the server status&amp;quot; do
    get &amp;quot;/up&amp;quot;
    assert last_response.ok?
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s run this test:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/time ruby minimal_test.rb
Run options: --seed 43022

# Running:

.

Finished in 0.066011s, 15.1490 runs/s, 15.1490 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
        1.32 real         0.57 user         0.49 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can&amp;#39;t get subsecond testing with Rails using hardware commonly used in a development
environment, like we did with Rack and Roda in my
&lt;a href=&quot;2024_10_25_creating_web_app_monoliths_that_boot_instantly_with_ruby&quot;&gt;previous article&lt;/a&gt;,
but we can get pretty close with a minimal Rails app. How about a full Rails app?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rails new full_rails_app
cd full_rails_app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add this test file to the project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# test/system/health_test.rb

require &amp;quot;application_system_test_case&amp;quot;

class HealthCheckTest &amp;lt; ApplicationSystemTestCase
  driven_by(:rack_test)

  test &amp;quot;returns the server status&amp;quot; do
    visit &amp;quot;/up&amp;quot;
    assert_selector &amp;quot;body&amp;quot;, style: &amp;quot;background-color: green&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s test it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/time bin/rails test:all
Running 1 tests in a single process (parallelization threshold is 50)
Run options: --seed 16351

# Running:

.

Finished in 0.141745s, 7.0549 runs/s, 7.0549 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
        2.48 real         1.13 user         1.02 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not that bad. This is what we can expect from a fresh full Rails app. If we can keep our
tests running that fast, that should be good enough.&lt;/p&gt;
&lt;h2&gt;How about Spring?&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;re reading this article, chances are that you are from the days where
&lt;a href=&quot;https://github.com/rails/spring&quot;&gt;Spring&lt;/a&gt; was added by default when you ran &amp;quot;rails new
app&amp;quot;. You might be asking: what about Spring?&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s add spring and measure again.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &amp;#39;gem &amp;quot;spring&amp;quot;, group: :development&amp;#39; &amp;gt;&amp;gt; Gemfile
bundle
bundle exec spring binstub

/usr/bin/time bin/spring rails test test/system
Running via Spring preloader in process 63159
Running 1 tests in a single process (parallelization threshold is 50)
Run options: --seed 14564

# Running:

.

Finished in 0.166576s, 6.0033 runs/s, 6.0033 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
        0.97 real         0.18 user         0.11 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yay, there we go, subsecond testing with Rails!&lt;/p&gt;
&lt;p&gt;Why can&amp;#39;t we use &amp;quot;bin/spring rails test:all&amp;quot; (or &lt;code&gt;test:system&lt;/code&gt;)? Spring supports specific
Rails commands such as &amp;quot;test&amp;quot;, &amp;quot;console&amp;quot; and &amp;quot;runner&amp;quot;, but not all commands by default.
Running &amp;quot;test:system&amp;quot;, &amp;quot;test:all&amp;quot;, &amp;quot;routes&amp;quot; and other commands will not go through the
Spring server.&lt;/p&gt;
&lt;p&gt;For those that don&amp;#39;t know what Spring is, it preloads the Rails app, initializes it
(boot) and waits for commands. This is the Spring server. Then, the Spring client will
send the commands to the server, which will then fork and run the command after the
application has already been initialized. That&amp;#39;s why it can complete tests in under a
second, since the app was already initialized when the command was run. It also watches
some files such as the initializers and will restart the server when those files change.&lt;/p&gt;
&lt;p&gt;Why isn&amp;#39;t Spring bundled with Rails by default anymore? I don&amp;#39;t really know, but Spring
is actually a hack. You have to extend it to support more commands, such as &amp;quot;rspec&amp;quot; and
&amp;quot;cucumber&amp;quot;, by installing additional gems, or write your own if you want to add support
for &amp;quot;test:system&amp;quot; and &amp;quot;test:all&amp;quot;, for example.&lt;/p&gt;
&lt;p&gt;There are over a hundred &lt;a href=&quot;https://github.com/rails/spring/issues&quot;&gt;open issues&lt;/a&gt; in the
Spring repository to this date, which indicates that such a hack is not as robust as
one might think. Having said that, if your application loads a lot of code (gems,
initializers, etc) during its initialization, adding Spring to your app can
significantly improve your test boot time with minimal effort. But if you&amp;#39;re able to
keep your boot fast, that&amp;#39;s certainly better since all commands will benefit from it,
not just those supported by Spring, and you avoid all Spring pitfalls.&lt;/p&gt;
&lt;h1&gt;Anti-patterns often used in Rails apps&lt;/h1&gt;
&lt;p&gt;Let&amp;#39;s talk about some common patterns found in old and big Rails apps that explain why
even very simple tests can take several seconds to complete. Those are most likely the
reason why a Rails app takes so long to boot.&lt;/p&gt;
&lt;h2&gt;Auto-required gems&lt;/h2&gt;
&lt;p&gt;In Rails, every gem added to the default and environment groups in Gemfile will be
automatically required during the application initialization. This happens through this
line in &lt;code&gt;config/application.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;Bundler.require(*Rails.groups)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;quot;Rails.groups&amp;quot; defaults to &lt;code&gt;[:default, &amp;quot;development&amp;quot;]&lt;/code&gt; when running Rails in the
development environment, for example.&lt;/p&gt;
&lt;p&gt;The more gems you add to the Gemfile default groups, the longer it will take for the
application to initialize. The application will boot faster if we add &amp;quot;require: false&amp;quot;
to the gem declaration, or if we create a separate group such as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# Gemfile
# ...
group :lazily_loaded_gems
  gem &amp;quot;graphql&amp;quot;
  gem &amp;quot;sidekiq&amp;quot;
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the production environment, and for the test environment when &lt;code&gt;ENV[&amp;quot;CI&amp;quot;]&lt;/code&gt; is
present, we could add the &lt;code&gt;:lazily_loaded_gems&lt;/code&gt; group to the default Rails groups. For
example, you can replace the &lt;code&gt;Bundler.require&lt;/code&gt; line in &lt;code&gt;config/application.rb&lt;/code&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# config/application.rb
# ...
bundler_groups = Rails.groups
bundler_groups &amp;lt;&amp;lt; :lazily_loaded_gems if Rails.env.production? || ENV[&amp;quot;CI&amp;quot;].present?

Bundler.require(*bundler_groups)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The downside is that this will force us to explicitly require those gems when our code
depends on them, or we&amp;#39;ll get errors in the development and test environments.&lt;/p&gt;
&lt;h2&gt;Rails initializers&lt;/h2&gt;
&lt;p&gt;Here&amp;#39;s what the documentation has to say about initializers:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://guides.rubyonrails.org/configuring.html%5C#using-initializer-files&quot;&gt;https://guides.rubyonrails.org/configuring.html\#using-initializer-files&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;After loading the framework and any gems in your application, Rails turns to loading
initializers. An initializer is any Ruby file stored under config/initializers in your
application. You can use initializers to hold configuration settings that should be
made after all of the frameworks and gems are loaded, such as options to configure
settings for these parts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Lots of gems will then suggest you to add some initializers to your project. The Devise
generator will add &lt;a href=&quot;https://github.com/RailsApps/rails-devise/blob/master/config/initializers/devise.rb&quot;&gt;this
initializer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &amp;quot;mongoid:config&amp;quot; generator will add another initializer. The &lt;code&gt;carrier_wave&lt;/code&gt; gem will
suggest another initializer to configure the gem. Same happens for many other gems such
as &lt;code&gt;airbrake&lt;/code&gt;, &lt;code&gt;simple_form&lt;/code&gt;, &lt;code&gt;draper&lt;/code&gt;, &lt;code&gt;geocoder&lt;/code&gt;, &lt;code&gt;kaminari&lt;/code&gt;, &lt;code&gt;money&lt;/code&gt; and many more
popular gems. Add to this the project&amp;#39;s own internal gems. Now, a very simple test to
check the &amp;quot;/up&amp;quot; health-check endpoint ends up loading lots of irrelevant code to the
test. As a result, such a single test would take a long time to complete.&lt;/p&gt;
&lt;p&gt;One should carefully decide whether it&amp;#39;s worth adding a new initializer to the
application. Adding an initializer is very simple and allows us to quickly move on, but
at the cost of slowing down the app&amp;#39;s boot a little bit more.&lt;/p&gt;
&lt;p&gt;Just like with the issue of gems getting required by default, we can opt out by avoiding
creating such initializers whenever possible. And the same drawback applies to this
case, as we&amp;#39;re supposed to initialize those gems whenever our code depends on them.&lt;/p&gt;
&lt;p&gt;For example, suppose we have the following initializer in our app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# config/initializers/airbrake.rb

Airbrake.configure do
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could instead replace it with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# we want to enable Airbrake during the application
# initialization in the production environment:
require &amp;quot;setup_airbrake&amp;quot; if Rails.env.production?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we create &amp;quot;lib/setup_airbrake.rb&amp;quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;quot;airbrake&amp;quot;
Airbrake.configure do
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Suppose we have some custom filter configured for Airbrake and we want to test it. Then,
in our test we would do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# spec/params_sanitizer_airbrake_filter_spec.rb
require &amp;quot;rails_helper&amp;quot;
require &amp;quot;setup_airbrake&amp;quot;

RSpec.describe ParamsSanitizerAirbrakeFilter do
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In many cases we can completely get rid of lots of initializers. For example, there&amp;#39;s no
need to initialize geocoder if we&amp;#39;re not using it. Just require &amp;quot;setup_geocoder&amp;quot; once
you depend on it somewhere.&lt;/p&gt;
&lt;p&gt;There are other cases where they can&amp;#39;t be easily avoided though. For example, some gems
must be loaded before we define the app&amp;#39;s routes, which happens during the
initialization. It doesn&amp;#39;t matter if our test isn&amp;#39;t exercising a GraphQL controller, or
some controller protected by Devise, we would still have to load both gems so that we
can define the app&amp;#39;s routes. Unfortunately I&amp;#39;m not aware of any tricks we could apply to
lazily load such code.&lt;/p&gt;
&lt;p&gt;How about &lt;code&gt;simple_form&lt;/code&gt;? It&amp;#39;s not required by the routes. What if you&amp;#39;re testing an
api-only controller? Is it required to load &lt;code&gt;simple_form&lt;/code&gt;? Well, an option would be to
prepend &lt;code&gt;ApplicationController&lt;/code&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;quot;setup_simple_form&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, if you&amp;#39;re testing some controller inheriting from &lt;code&gt;APIController&lt;/code&gt; instead, then
it won&amp;#39;t load &lt;code&gt;simple_form&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Surely this approach requires discipline but it also enables your individual tests to
complete much faster since they no longer must require all of the application&amp;#39;s
dependencies if the code you&amp;#39;re testing does not depend on them.&lt;/p&gt;
&lt;h2&gt;RSpec support files&lt;/h2&gt;
&lt;p&gt;This is similar to the Rails initializer pattern. Up to &lt;code&gt;rspec-rais&lt;/code&gt; 3.0.2, released 10
years ago, we had the following line in &lt;code&gt;spec/rails_helper.rb&lt;/code&gt; enabled by default:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;Dir[Rails.root.join(&amp;quot;spec/support/**/*.rb&amp;quot;)\].each { |f| require f }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your app is that old, chances are good that you have such a line still enabled in
your project and it leads to the same sort of issues as the Rails initializers described
above.&lt;/p&gt;
&lt;p&gt;These days such a line is commented by default in the generated file. See the relevant
snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Rails.root.glob(&amp;#39;spec/support/**/*.rb&amp;#39;).sort_by(&amp;amp;:to_s).each { |f| require f }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some people will ignore the warning and uncomment that line to these days and will
experience the same issue with boot time performance when running individual tests.&lt;/p&gt;
&lt;p&gt;Another possibility would be to create a similar tool to the &lt;code&gt;spring&lt;/code&gt; gem. That tool
would load all support files and start a server waiting for a command to run some tests.
Then it would fork the process and load the requested tests much faster. It should
restart the server whenever the support files change. I don&amp;#39;t think such a tool exists
yet, but the effort to create one would be similar to creating the &lt;code&gt;spring&lt;/code&gt; gem. Not
trivial, but not that much complicated either. It&amp;#39;s certainly doable.&lt;/p&gt;
&lt;p&gt;Alternatively, the following simple script would speed up running your tests multiple
times. Despite the name, it doesn&amp;#39;t really watch for file changes like
&lt;a href=&quot;https://github.com/guard/guard&quot;&gt;guard&lt;/a&gt;, although such a feature could be added to the
script, but I wanted to keep it simple since this article is already long enough. It&amp;#39;s
important to change &lt;code&gt;config.enable_reloading&lt;/code&gt; in &lt;code&gt;config/environments/test.rb&lt;/code&gt; to
something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;config.enable_reloading = ENV[&amp;quot;WATCHING_SPECS&amp;quot;] || defined?(Spring)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, such script should work fine in most cases:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;#!/usr/bin/env ruby -I spec

require &amp;quot;bundler/setup&amp;quot;
ENV[&amp;quot;BOOTSNAP_CACHE_DIR&amp;quot;] = File.expand_path &amp;quot;../tmp/cache&amp;quot;, __dir__
require &amp;quot;bootsnap/setup&amp;quot;
require &amp;quot;rspec/core&amp;quot;

ENV[&amp;quot;WATCHING_SPECS&amp;quot;] = &amp;quot;true&amp;quot;

require &amp;quot;rails_helper&amp;quot;

ActiveRecord::Base.connection_pool.disconnect

ARGV &amp;lt;&amp;lt; &amp;quot;spec&amp;quot; if ARGV.empty?
last_specs = ARGV

while true
  Process.fork do
    RSpec::Core::Runner.run last_specs
  end
  Process.wait

  puts &amp;quot;Which tests to run? Press ENTER to run the same previous tests: #{last_specs}.\n&amp;quot; +
    &amp;quot;Enter &amp;#39;exit&amp;#39; or Ctrl+D to stop. &amp;#39;reset&amp;#39; to run the original tests: #{ARGV}.&amp;quot;
  specs = STDIN.gets&amp;amp;.chomp&amp;amp;.split(&amp;quot; &amp;quot;)
  break if specs.nil? || specs == [ &amp;quot;exit&amp;quot; ]
  specs = last_specs if specs.empty?
  specs = ARGV if specs == [ &amp;quot;reset&amp;quot; ]
  specs = specs.map do |spec|
    next spec if spec.start_with?(&amp;#39;-&amp;#39;)
    spec.start_with?(&amp;quot;spec&amp;quot;) ? spec : &amp;quot;spec/#{spec}&amp;quot;
  end

  last_specs = specs

  RSpec.configuration.start_time = Time.now

  Rails.application.reloader.reload!
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ten years ago we had &lt;a href=&quot;https://github.com/sporkrb/spork&quot;&gt;spork&lt;/a&gt; which took a similar
approach to Spring, towards improving test boot time, but that project seems to be dead
since then. The &lt;code&gt;rspec-rails&lt;/code&gt; gem also used to provide a &lt;code&gt;script/spec_server&lt;/code&gt; script by
that time with similar goals. As we can see, the Rails boot time has been a concern for
over a decade. Hopefully it will get fixed once and for all some day.&lt;/p&gt;
&lt;h2&gt;Factories with provided classes&lt;/h2&gt;
&lt;p&gt;With FactoryBot one can specify which class to use for a particular factory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;FactoryBot.define do
  factory :fat_model do
    name { &amp;quot;MyText&amp;quot; }

    factory :fat_model_subclass, class: FatModelSubclass do
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This causes FatModelSubclass to be loaded with all its dependencies (FatModel) when
loading the factory&amp;#39;s definitions, even if we&amp;#39;re not using that factory. There are
better ways to ensure the class will be lazily loaded, once the factory is actually
used:&lt;/p&gt;
&lt;p&gt;Example 1 --- pass class as a string to be lazily loaded when needed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;factory :fat_model_subclass, class: &amp;quot;FatModelSubclass&amp;quot; do
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://thoughtbot.github.io/factory_bot/defining/explicit-class.html&quot;&gt;This is documented by the way&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can pass a constant as well, if the constant is available (note that this can
cause test performance problems in large Rails applications, since referring to the
constant will cause it to be eagerly loaded).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Example 2 --- use &lt;code&gt;initialize_with&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;FactoryBot.define do
  factory :fat_model do
    name { &amp;quot;MyText&amp;quot; }
    transient do
      klass { FatModel }
    end

    initialize_with { klass.new }

    # factory :fat_model_subclass, class: &amp;quot;FatModelSubclass&amp;quot; do
    factory :fat_model_subclass do
      klass { FatModelSubclass }
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second approach allows some code editors to go to the model definition by using some
shortcut such as &lt;code&gt;Ctrl/Cmd + Click&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Rails limitations&lt;/h1&gt;
&lt;h2&gt;Routes&lt;/h2&gt;
&lt;p&gt;Sometimes we just want to test some models, but some dependency would rely on Rails
somehow (a secret, setting or environment, for example) and we end up requiring
&amp;quot;rails_helper&amp;quot; even though we&amp;#39;re not making any requests. But we still must initialize
the Rails app, and it happens to load the routes, which can take a significant time in
large apps.&lt;/p&gt;
&lt;p&gt;This has been fixed in Rails 8 (not released yet to the date of publication of this
article) but in the meanwhile, we can use the &lt;a href=&quot;https://github.com/amatsuda/routes_lazy_routes&quot;&gt;routes_lazy_routes
gem&lt;/a&gt;, by Akira Matsuda:&lt;/p&gt;
&lt;p&gt;In Gemfile, we add:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;group :development, :test do
  gem &amp;#39;routes_lazy_routes&amp;#39;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that change alone, running &amp;quot;bin/rails environment&amp;quot; goes from 2.5s to 1.9s.&lt;/p&gt;
&lt;p&gt;Even though it speeds up some Rails commands, it will still load the routes when we&amp;#39;re
testing some model after requiring &lt;code&gt;rails_helper&lt;/code&gt;, simply because that gem has this in
its initializer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;ActiveSupport.on_load :action_dispatch_integration_test, run_once: true do
  RoutesLazyRoutes.eager_load!
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Surely, it could be adapted for this use case, but to be honest, it&amp;#39;s better to wait for
Rails 8 release date.&lt;/p&gt;
&lt;h2&gt;Mountable Engines&lt;/h2&gt;
&lt;p&gt;Once you run the &amp;quot;graphql:install&amp;quot; generator, it will add the &amp;quot;graphiql-rails&amp;quot; gem to
the development group. It&amp;#39;s a mountable Rails Engine. I don&amp;#39;t know how we could possibly
lazily load mountable engines in a Rails application. If your app depends on many
mountable engines, they will end up adding to the boot time, since you must load them
during the app&amp;#39;s initialization. If you know how to lazily load them, please let me know
in the comments.&lt;/p&gt;
&lt;h1&gt;Profiling&lt;/h1&gt;
&lt;p&gt;When we&amp;#39;re investigating what&amp;#39;s causing some code to be slow, it&amp;#39;s very important to
profile the relevant code. If we want to know why boot is taking a long time, we want to
profile at least:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;require &amp;quot;bundler/setup&amp;quot; --- There&amp;#39;s usually little we can do about it unless you&amp;#39;re
intending to work directly on the Bundler&amp;#39;s source-code;&lt;/li&gt;
&lt;li&gt;Bundler.require(...) --- We can decide which gems should be loaded when this method is
called by making changes to either Gemfile or to the code calling &lt;code&gt;Bundler.require&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Rails initializers ---  There are two simple ways one can measure this. One of them
would be to create a single initializer that would load the initializers from another
path and measure how long they take to complete. The other one is installing the gem
&lt;code&gt;bumbler&lt;/code&gt; which I&amp;#39;ll discuss briefly in the next section. Or we can simply profile the
next items in this list, which should include the time spent on initializers:&lt;/li&gt;
&lt;li&gt;require &amp;quot;config/environment&amp;quot;&lt;/li&gt;
&lt;li&gt;Rails.application.initialize!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Bumbler&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nevir/Bumbler&quot;&gt;Bumbler&lt;/a&gt; is a tool that allows us to quickly inspect
how much time is spent on initializers and required gems:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bundle exec bumbler --initializers # display initializers
# specify a minimal threshold with -t 20 to display only initializers taking over 20ms to load.
bundle exec bumbler --initializers -t 20
# display all loaded gems:
bundle exec bumbler --all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It doesn&amp;#39;t provide as many details as the flamegraphs generated by Stackprof, but they
can quickly provide you with some hints on what&amp;#39;s going on with your app&amp;#39;s boot.&lt;/p&gt;
&lt;h2&gt;Stackprof&lt;/h2&gt;
&lt;p&gt;I prefer to profile code using flamegraphs, so my suggestion is to add the
&lt;a href=&quot;https://github.com/tmm1/stackprof&quot;&gt;stackprof&lt;/a&gt; gem to Gemfile and instrument the
relevant code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;stackprof&amp;#39;
require &amp;#39;json&amp;#39;

GC.disable
profile = StackProf.run(raw: true) do
  Rails.application.initialize!
end

File.write &amp;quot;profile-application-initialize.json&amp;quot;, JSON.unparse(profile)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can use another tool to view the flamegraphs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm -g speedscope
speedscope profile-application-initialize.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The stackprof&amp;#39;s README mentions another way to generate and visualize the flamegraphs,
but I couldn&amp;#39;t make it work in my environment, while
&lt;a href=&quot;https://github.com/jlfwong/speedscope&quot;&gt;speedscope&lt;/a&gt; did the trick for me.&lt;/p&gt;
&lt;p&gt;If you decided to profile your app&amp;#39;s boot process in Linux or Mac OS, you probably
noticed that loading the timezone datasource takes over 100 ms in the Rails boot. To save
that time I&amp;#39;d recommend you to add the &lt;code&gt;tzinfo-data&lt;/code&gt; gem to Gemfile. Rails by default
adds this to Gemfile:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem &amp;quot;tzinfo-data&amp;quot;, platforms: %i[ windows jruby ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this gem as the datasource will load much faster in Linux/Mac compared to loading
the datasource from the system files, so I&amp;#39;d recommend adding this gem to Gemfile for
all platforms if you want to speed up your boot time as much as possible. If you still
wants to use the system files as the datasource for the production environment, just add
this line for this environment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;TZInfo::DataSource.set :zoneinfo
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Just like mentioned in my &lt;a href=&quot;2024_10_25_creating_web_app_monoliths_that_boot_instantly_with_ruby&quot;&gt;previous
article&lt;/a&gt;, the key
for fast booting is lazily loading code. Loading code takes time, so the more code you
can avoid loading during the app initialization, the faster it will boot. Avoid
initializers as much as you can, require gems only once you need them and you should
benefit from being able to run individual tests pretty fast.&lt;/p&gt;
&lt;p&gt;Adding the spring gem to the project could also save you a few seconds running your
tests. A &amp;quot;bin/watch-specs&amp;quot; script was provided to get a similar experience focused on
speeding up the tests boot time.&lt;/p&gt;
&lt;p&gt;Finally, I created a &lt;a href=&quot;https://github.com/rosenfeld/fast_boot_app&quot;&gt;repository&lt;/a&gt; with all
changes discussed in this article to help you explore what it means in practice. Check
it out and try it by yourself. It may be easier to follow the project by inspecting the
&lt;a href=&quot;https://github.com/rosenfeld/fast_boot_app/commits/main/&quot;&gt;git logs&lt;/a&gt; and see the changes
one by one.&lt;/p&gt;
&lt;p&gt;If you have any other suggestions to improve the boot performance, please let us know in
the comments. I&amp;#39;d love to hear about them.&lt;/p&gt;
&lt;p&gt;Good luck improving your app&amp;#39;s boot performance.&lt;/p&gt;
</content:encoded></item><item><title>Creating web app monoliths that boot instantly with Ruby</title><link>https://rosenfeld.page/articles/ruby-rails/2024_10_25_creating_web_app_monoliths_that_boot_instantly_with_ruby/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2024_10_25_creating_web_app_monoliths_that_boot_instantly_with_ruby/</guid><pubDate>Fri, 25 Oct 2024 20:35:00 GMT</pubDate><content:encoded>&lt;p&gt;What if I told you that it&amp;#39;s not only possible, but actually pretty simple, to write a
huge monolith web app that boots in under a second using Ruby?&lt;/p&gt;
&lt;p&gt;Also, it doesn&amp;#39;t matter how big it grows, it will still boot in under a second. So,
what&amp;#39;s the catch? How can it work?&lt;/p&gt;
&lt;p&gt;Well, the key thing to boot quickly, whichever stack you pick, is to lazily load as much
as you can. If you architecture your web app to load everything lazily, then it will
boot at no time.&lt;/p&gt;
&lt;p&gt;This is a long article, feel free to jump ahead to the last section if you&amp;#39;re only
curious about the solution.&lt;/p&gt;
&lt;h1&gt;Why does boot time matter?&lt;/h1&gt;
&lt;p&gt;You may have been wondering: &amp;quot;so, what&amp;#39;s the point of lazily loading everything? It&amp;#39;s
still going to spend time loading slow code when serving a request!&amp;quot;. And you&amp;#39;re
right! But it doesn&amp;#39;t mean that instant boot isn&amp;#39;t valuable at all.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re adopting canary deployment, for example, it doesn&amp;#39;t really matter too much if
your deployment takes 20 minutes or an hour to happen. Unless you need to deploy an
urgent fix (security patch or severe bug), of course!&lt;/p&gt;
&lt;p&gt;However, during the development of the application, the boot time matters a lot! I&amp;#39;ve
worked in apps that would take several seconds to boot before I could start using the
app and add features or fix bugs, that&amp;#39;s a terrible experience, but it&amp;#39;s not that much
of an issue if it only happens once in a while and code reloading happens pretty fast.&lt;/p&gt;
&lt;h2&gt;Automated tests benefit a lot from fast boot&lt;/h2&gt;
&lt;p&gt;The main benefit of having quick boot though is the ability of running individual
automated tests very quickly.&lt;/p&gt;
&lt;p&gt;Imagine yourself hunting some hard-to-debug flaky test. You&amp;#39;re probably going to run it
many many times until you can figure out what&amp;#39;s causing it to fail sometimes. This is
how the process usually goes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you&amp;#39;re lucky, you&amp;#39;re able to reproduce by specifying the same seed reported by CI,
so you run the test with the seed and confirm it&amp;#39;s failing locally too;&lt;/li&gt;
&lt;li&gt;You make some changes to the code or to the test, in an attempt to detect the reason
why it&amp;#39;s failing;&lt;/li&gt;
&lt;li&gt;You run the test again;&lt;/li&gt;
&lt;li&gt;Repeat steps 2 and 3 several times until you find the culprit and fix the flaky test.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If your test takes 30 secs just to boot your app before you test it, that means fixing
the flaky test will take 10 minutes at least only running the tests if you repeat steps
2 and 3 20 times. Add to this the frustration of having to wait over 30 secs before you
know if your last attempted change resulted in any progress.&lt;/p&gt;
&lt;p&gt;What if your app boots instantly and only 3 secs are required to load all dependencies
for the particular request you&amp;#39;re exercising in your test? Suddenly, if you repeat the
steps 20 times it will only take 1 minute running your test, compared to the 10 minutes
from the previous scenario. And you only need to wait for 3 secs before you know if your
change resulted in any progress. And it feels even better in tests where loading all
required dependencies takes less than a second.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s the main advantage of lazily loading your code!&lt;/p&gt;
&lt;h2&gt;Rake tasks also benefit from fast boot&lt;/h2&gt;
&lt;p&gt;If some of your Rake tasks rely on booting your app first, then running that task will
take over 30 secs, if this is what it takes to boot your app. Even if your task doesn&amp;#39;t
require all dependencies loaded during the boot process.&lt;/p&gt;
&lt;p&gt;As an example, if you&amp;#39;re working on a Rails app and run the &lt;code&gt;routes&lt;/code&gt; task, it will
require the app to boot. It&amp;#39;s not exactly a Rake task but the idea is the same: you&amp;#39;re
running a task that relies on your app being booted. If your app takes 15 secs to boot,
&lt;code&gt;bin/rails routes&lt;/code&gt; will also take 15 secs to run.&lt;/p&gt;
&lt;h1&gt;Automatic setup has drawbacks&lt;/h1&gt;
&lt;p&gt;I&amp;#39;ve been interviewing Ruby candidates in the past few weeks and I often ask them what
they like in Rails and almost every candidate tells me that &amp;quot;things just work in Rails&amp;quot;.
No configuration required. No manual setup. This is perceived by most people as a great
advantage in Rails over the alternatives.&lt;/p&gt;
&lt;p&gt;After all, it&amp;#39;s a great feeling to start working on some app you&amp;#39;ve never seen before
and you know exactly where to look when you&amp;#39;re searching for controllers, models,
routes, settings and tests, right?&lt;/p&gt;
&lt;p&gt;Conventions are great, indeed, I agree. But sometimes people will abuse from automatic
setup (in my opinion, of course).&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take the &lt;code&gt;web-console&lt;/code&gt; gem, bundled with Rails by default, as an example. Once
you require the gem, it will install a bunch of hooks, by calling
&lt;code&gt;Rails::Railtie.initialize&lt;/code&gt; with blocks that will add a middleware to the app, among
other initialization tasks. Rails engines assume the existence of a singleton Rails
application (&lt;code&gt;Rails.application&lt;/code&gt;). During the boot process, this singleton app will call
those hooks registered by the required Rails engines, such as
&lt;a href=&quot;https://github.com/rails/web-console/blob/main/lib/web_console/railtie.rb&quot;&gt;web-console&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the sake of easiness, lots of Rails engines follow this pattern for automatic setup.
So, instead of providing users with instructions on how to add the provided middlewares
to the app, those engines will automatically add the middleware for you. All you have to
do is &lt;code&gt;bundle add web-console&lt;/code&gt; and you&amp;#39;re done. No need to perform any extra steps,
super easy!&lt;/p&gt;
&lt;p&gt;But such a feature doesn&amp;#39;t come for free. First, Rails will load all gems from Gemfile
in the default and environment groups by default. The default group is the one
containing all gems declared in the top-level group. You can create as many groups in
Gemfile as you want and Rails will automatically load the default and &amp;quot;test&amp;quot; groups by
default when you load the application in the test environment.&lt;/p&gt;
&lt;p&gt;Rails calls &lt;code&gt;Bundler.require(*Rails.groups)&lt;/code&gt; in &lt;code&gt;config/application.rb&lt;/code&gt;, which
loads all project&amp;#39;s gems by default for the selected environment. So, unless you create
a separate group for gems you want to lazily load, you must explicitly add &lt;code&gt;require: false&lt;/code&gt; to the gem declaration.&lt;/p&gt;
&lt;p&gt;By the way, by no means I&amp;#39;m suggesting there&amp;#39;s a problem with the &lt;code&gt;web-console&lt;/code&gt;
railtie itself. After all, it&amp;#39;s only loaded in the development environment by default,
and you can even configure it to mount in an arbitrary path if you dislike the default
one (&amp;quot;/__web_console&amp;quot;). I&amp;#39;m more worried about the available pattern, which can be
abused by Rails engines.&lt;/p&gt;
&lt;h2&gt;Automatic setup makes lazy loading nearly impossible sometimes&lt;/h2&gt;
&lt;p&gt;If your app is designed in a similar way as Rails engines work, and dependencies rely on
the ability of hooking into the boot process, then you can&amp;#39;t lazily load that dependency
if it has to be required during the boot phase.&lt;/p&gt;
&lt;h2&gt;The top-level app should have minimal dependencies&lt;/h2&gt;
&lt;p&gt;Rack allows applications to mount other Rack applications on top of it. That allows us
to build a monolith consisting of many Rack apps, mounted on the top of the main app.&lt;/p&gt;
&lt;p&gt;This is a good step in the direction of achieving instant boot, however, it&amp;#39;s not an
enough condition. Unless you&amp;#39;re able to lazily load those apps, you still must load them
with their dependencies, and you won&amp;#39;t achieve instant boot.&lt;/p&gt;
&lt;p&gt;If you add a dependency to the top-level route definitions, it will add to the boot
time. Unless you architect your app in a way that allows you to lazily load your
dependencies, you can&amp;#39;t guarantee that it will boot instantly even if it gets huge with
hundreds or thousands of dependencies.&lt;/p&gt;
&lt;p&gt;For example, you can&amp;#39;t lazily load Devise in a Rails application (try it if you don&amp;#39;t
believe me). So, even if you want to test some model, you have to pay the cost of
loading Devise and all its dependencies because in Rails the models also require the
application to be initialized (in a typical setup).&lt;/p&gt;
&lt;p&gt;If you know how to design a Rails app to always initialize in under 2s, no matter how
big it gets, please let me know in the comments. For the remainder of this article, I&amp;#39;m
assuming it&amp;#39;s not currently possible with Rails, so I&amp;#39;m going to provide examples with
alternative libraries.&lt;/p&gt;
&lt;h1&gt;Hands-on: let&amp;#39;s build a web application with instant boot&lt;/h1&gt;
&lt;h2&gt;How fast is Ruby?&lt;/h2&gt;
&lt;p&gt;If our goal is to boot our app within a second, we must first check whether Ruby can run
boot itself that fast:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/time ruby -e &amp;#39;&amp;#39;
        0.27 real         0.07 user         0.04 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awesome! We have 730 ms left to use in our own code. Let&amp;#39;s add a few dependencies and
see how much is left:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOTSNAP_CACHE_DIR=tmp/cache /usr/bin/time ruby -r bundler/setup -r bootsnap/setup -e &amp;#39;&amp;#39;
        0.59 real         0.24 user         0.16 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s fine, we still have 410 ms left for our code. Can we load Rails within 410 ms?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOTSNAP_CACHE_DIR=tmp/cache /usr/bin/time ruby -r bundler/setup -r bootsnap/setup \
    -r rails -r action_controller/railtie \
    -e &amp;#39;class MyApp &amp;lt; Rails::Application; config.api_only = true; end; MyApp.initialize!&amp;#39;
        1.27 real         0.51 user         0.50 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nope, if we really want to boot within a second, we can&amp;#39;t use Rails. Less than 2 secs is
still good enough, however there are many more serious reasons why we can&amp;#39;t guarantee
fast booting with big Rails apps, which I&amp;#39;ll explore in-depth in
&lt;a href=&quot;2024_10_25_why_is_your_rails_app_boot_slow&quot;&gt;another article&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Bare Rack app example&lt;/h2&gt;
&lt;p&gt;In the beginning of the article I said it was not only possible, but simple to write a
web app with instant boot in Ruby. Let&amp;#39;s start demonstrating how it can be achieved with
a pure Rack app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# config.ru

require &amp;quot;rack/builder&amp;quot;
app = Rack::Builder.new do
  map &amp;quot;/up&amp;quot; do
    run lambda { |env| [ 200, { &amp;#39;content-type&amp;#39; =&amp;gt; &amp;#39;application/json&amp;#39; }, [ &amp;#39;{ &amp;quot;status&amp;quot;: &amp;quot;ok&amp;quot; }&amp;#39; ] ] }
  end

  map &amp;quot;/heavy_app&amp;quot; do
    run lambda { |env|
      require_relative &amp;quot;config/environment&amp;quot;
      Rails.application.call env
    }
  end
  # as many map blocks here as big your monolith grows
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the idea is to split the huge app into many smaller apps. If you
exercise the &amp;quot;/heavy_app&amp;quot; endpoint in some test, of course it will take longer to
complete if the app responding to that endpoint is a heavy one. However, if you&amp;#39;re
running some test to check the &amp;quot;/up&amp;quot; endpoint, then it will complete in under a second.&lt;/p&gt;
&lt;p&gt;This is extremely useful when working on individual tests. Ideally we should be only
loading what the test is exercising. That way, we avoid having to wait for over 10
seconds every time we need our app to boot even if we only require a few dependencies to
test what we want.&lt;/p&gt;
&lt;p&gt;You might be concerned that this could lead to uncaught bugs in production because we
may have forgotten to require something and the app could break in production if some
requests were made in a different order. Or maybe you&amp;#39;d just prefer to eagerly load
everything in production, like Rails does by default.&lt;/p&gt;
&lt;p&gt;While it&amp;#39;s simple to modify the app above to support that feature (and eager load the
app when running all tests in CI), I&amp;#39;m assuming you can do that by yourself, and I&amp;#39;ll
present yet another solution using a Roda app, adding auto-reloading and eager loading
support.&lt;/p&gt;
&lt;h2&gt;A Roda app example&lt;/h2&gt;
&lt;p&gt;Roda is a library created by Jeremy Evans, the maintainer of the (not so) popular Sequel
gem. &lt;a href=&quot;2017_05_01_feeling_alone_in_the_ruby_community_and_replacing_rails_with_roda&quot;&gt;I&amp;#39;ve written about it already years ago&lt;/a&gt;,
so in this article I&amp;#39;m going to focus on the solution itself.&lt;/p&gt;
&lt;p&gt;I know many of you enjoy automatic code loading, so I&amp;#39;ll add the &lt;code&gt;zeitwerk&lt;/code&gt; gem to
provide both auto-reloading and auto-loading features to this app, the same way it works
in a standard Rails app. Personally I&amp;#39;m not a fan of autoloading, so I use the
&lt;a href=&quot;https://github.com/rosenfeld/auto_reloader&quot;&gt;auto_reloader&lt;/a&gt; gem instead (authored by me,
by the way), but it&amp;#39;s a matter of preference. &lt;a href=&quot;2016_07_18_autoreloader_a_transparent_automatic_code_reloader_for_ruby&quot;&gt;I&amp;#39;ve written about it before
too&lt;/a&gt;.
It doesn&amp;#39;t really matter for the purpose of building a huge monolith with instant boot.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re also using a very useful Roda plugin called
&lt;a href=&quot;https://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/MultiRun.html&quot;&gt;multi_run&lt;/a&gt; in
this example.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start by adding all dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir my-huge-app
cd my-huge-app
git init
bundle init
bundle add puma roda zeitwerk rack-test cucumber ostruct logger
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In case you&amp;#39;re curious, some of the dependencies rely on &lt;code&gt;ostruct&lt;/code&gt; and &lt;code&gt;logger&lt;/code&gt; but
don&amp;#39;t explicitly depend on them, and they are no longer bundled with newer Ruby
releases.&lt;/p&gt;
&lt;p&gt;Then we&amp;#39;re going to create an useful boot file that we can load in our tests too:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# boot.rb

require &amp;quot;bundler/setup&amp;quot;
ENV[&amp;quot;BOOTSNAP_CACHE_DIR&amp;quot;] ||= &amp;quot;tmp/cache&amp;quot;
require &amp;quot;bootsnap/setup&amp;quot;
require &amp;quot;zeitwerk&amp;quot;

APP_ENV = ENV[&amp;quot;RACK_ENV&amp;quot;] || &amp;quot;development&amp;quot;
loader = Zeitwerk::Loader.new
loader.push_dir File.expand_path(&amp;quot;app&amp;quot;, __dir__)
loader.enable_reloading if APP_ENV == &amp;quot;development&amp;quot;
loader.setup

loader.eager_load if APP_ENV == &amp;quot;production&amp;quot; || ENV[&amp;quot;CI&amp;quot;]

AppLoader = loader
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;m keeping this example very simple, but in a real app you&amp;#39;d be interested in using a
proper &lt;code&gt;Settings&lt;/code&gt; class, in which you&amp;#39;d configure the wanted behavior by environment,
such as enabling auto-reloading and eager-loading, for example.&lt;/p&gt;
&lt;p&gt;Now, the top-level app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# app/apps/main.rb

require &amp;quot;roda&amp;quot;

module Apps
  class Main &amp;lt; Roda
    plugin :json
    plugin :multi_run

    route do |r|
      r.get &amp;quot;up&amp;quot; do
        { status: &amp;quot;ok&amp;quot;, env: APP_ENV }
      end

      run_app &amp;quot;some_path&amp;quot;, -&amp;gt;{ Apps::SomeApp }
      run_app &amp;quot;another_path&amp;quot;, -&amp;gt; { Apps::AnotherApp }

      # or something like:
      Dir[File.expand_path(&amp;quot;config/subapps/*.rb&amp;quot;, APP_ROOT)].each{ |subapp| load subapp }
    end

    def self.run_app(path, app)
      if APP_ENV == &amp;quot;production&amp;quot; || ENV[&amp;quot;CI&amp;quot;]
        request.run path, app[]
      else
        request.run path, -&amp;gt;(env) {
          app[].freeze.app.call env
        }
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally the web server entry point:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# config.ru

require_relative &amp;#39;boot&amp;#39;

if APP_ENV == &amp;quot;development&amp;quot;
  run lambda { |env|
    AppLoader.reload
    Apps::Main.freeze.app.call env
  }
else
  run Apps::Main.freeze.app
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, it&amp;#39;s a really simple setup that allows you to boot a huge app in under a
second. Go ahead and add tons of gems to Gemfile and notice how the app will still boot
instantly. Add as many apps to it, add some &lt;code&gt;&amp;quot;sleep 10&amp;quot;&lt;/code&gt; statements to them, and you
should still notice the immediate boot.&lt;/p&gt;
&lt;h3&gt;Testing the app&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s now time to see one of the main benefits of this approach by testing it.&lt;/p&gt;
&lt;p&gt;For the sake of simplicity, I&amp;#39;m using &lt;code&gt;test/unit&lt;/code&gt; to test it, but you should get the
same results with RSpec.&lt;/p&gt;
&lt;p&gt;test/test_runner.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require_relative &amp;quot;test_helper&amp;quot;

exit Test::Unit::AutoRunner.run(true, __dir__)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;test/test_helper.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require_relative &amp;quot;../boot&amp;quot;
require &amp;quot;test/unit&amp;quot;
require &amp;quot;rack/test&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;test/integration/health_test.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require_relative &amp;quot;../test_helper&amp;quot; # allows for `ruby test/integration/health_test.rb`

class HealthTest &amp;lt; Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    Apps::Main.freeze.app
  end

  def test_response_is_ok
    get &amp;quot;/up&amp;quot;
    assert last_response.ok?
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You don&amp;#39;t need &lt;code&gt;require_relative &amp;quot;../test_helper&amp;quot;&lt;/code&gt; in your tests if you&amp;#39;re just using
&lt;code&gt;ruby test/test_runner.rb&lt;/code&gt;, but it simplifies running those test files individually by
simply calling &lt;code&gt;ruby test/integration/health_test.rb&lt;/code&gt; instead of &lt;code&gt;ruby test/run_test.rb --location test/integration/health_test.rb&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The test runs instantly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/time ruby test/run_test.rb
Loaded suite test
Started
Finished in 0.008055 seconds.
-------------------------------------------------------------------------------------
1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-------------------------------------------------------------------------------------
124.15 tests/s, 124.15 assertions/s
        0.77 real         0.34 user         0.22 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow! That was fast! Not only does the application boot in less than a second, but we
can also test it within a second.&lt;/p&gt;
&lt;h3&gt;How about Cucumber?&lt;/h3&gt;
&lt;p&gt;Testing straightforward requests with test/unit completes within a second, but can we
also achieve subsecond testing with Cucumber? Well, let&amp;#39;s give it a try, shall we?&lt;/p&gt;
&lt;p&gt;First we run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bundle binstubs --all
bin/cucumber --init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s edit &lt;code&gt;features/support/env.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require_relative &amp;#39;../../test/test_helper&amp;#39;

module CucumberApp
  def app
    @app ||= Apps::Main.freeze.app
  end
end

World(Test::Unit::Assertions)
World(Rack::Test::Methods)
World(CucumberApp)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s create a simple test (&lt;code&gt;features/health.feature&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gherkin&quot;&gt;Feature: Health check

  Scenario: Health check monitoring
    Given a monitoring service checks for the application health state
    Then it responds with the current status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the step definitions for this test (&lt;code&gt;features/step_definitions/health.rb&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;Given(&amp;#39;a monitoring service checks for the application health state&amp;#39;) do
  get &amp;quot;/up&amp;quot;
end

Then(&amp;#39;it responds with the current status&amp;#39;) do
  assert last_response.ok?
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s run the test:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/time bin/cucumber
Using the default profile...
Feature: Health check

  Scenario: Health check monitoring                                    # features/health.feature:3
    Given a monitoring service checks for the application health state # features/step_definitions/health.rb:3
    Then it responds with the current status                           # features/step_definitions/health.rb:7

1 scenario (1 passed)
2 steps (2 passed)
0m0.013s
        1.07 real         0.53 user         0.32 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow, that was really close! Maybe it&amp;#39;s time to ask my company for a hardware upgrade.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;In this article we&amp;#39;ve seen that with some simple architecture we can achieve instant
boot while designing a Ruby web application, no matter how big it gets, as long as we
lazily load our code. We&amp;#39;ve also seen how it allows us to run individual simple tests
very quickly.&lt;/p&gt;
&lt;p&gt;We have also briefly discussed how such an approach would be a challenge to implement in
a Rails app. In my &lt;a href=&quot;2024_10_25_why_is_your_rails_app_boot_slow&quot;&gt;next article&lt;/a&gt; I&amp;#39;ll explore what we can do to improve the boot time of
Rails applications by applying the same idea of lazy loading as much as we can.&lt;/p&gt;
</content:encoded></item><item><title>LightBlog: a file-based blog app</title><link>https://rosenfeld.page/articles/2023_03_01_lightblog_a_file_based_blog_app/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2023_03_01_lightblog_a_file_based_blog_app/</guid><pubDate>Wed, 01 Mar 2023 13:14:00 GMT</pubDate><content:encoded>&lt;p&gt;When Heroku discontinued the free plan, I decided to host my site elsewhere. It was an old Rails
app, and since I moved from Rails to Roda a few years ago for the apps I maintain, I decided to
take the opportunity to rewrite the blog in Roda.&lt;/p&gt;
&lt;p&gt;While doing so, I thought it could be a good idea to make the bulk of it an open-source project,
and that&amp;#39;s how &lt;a href=&quot;https://github.com/rosenfeld/light_blog&quot;&gt;LightBlog&lt;/a&gt; was born. This site is powered
by LightBlog with a few changes to support multiple languages (namely English and Portuguese) and
automatic code-reloading
(using my &lt;a href=&quot;https://github.com/rosenfeld/auto_reloader&quot;&gt;auto_reloader gem&lt;/a&gt;), plus a few changes to
the default views.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s basically a Roda application using the
&lt;a href=&quot;https://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/MultiRun.html&quot;&gt;multi_run&lt;/a&gt; plugin to
serve two LightBlog apps, one for the English articles and another one for the Portuguese articles
with a slightly different configurations passed to &lt;code&gt;LightBlog.create_app&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;How it works?&lt;/h2&gt;
&lt;p&gt;LightBlog (and my previous Rails-based site) is inspired by
&lt;a href=&quot;https://github.com/cloudhead/toto&quot;&gt;Toto&lt;/a&gt;, a git-powered, minimalist blog engine.&lt;/p&gt;
&lt;p&gt;Just like it happens in Toto, articles are written in Markdown and stored directly on disk
(usually in a Git repository) and contain some metadata associated to it in the form of a
header written in YAML, containing arbitrary information besides the article title and published /
updated at dates.&lt;/p&gt;
&lt;p&gt;The articles history is basically the git history of the articles repository. When using LightBlog
to serve your articles, I&amp;#39;d strongly recommend you to keep your articles in a separate repository.&lt;/p&gt;
&lt;p&gt;This approach provides many benefits:&lt;/p&gt;
&lt;h3&gt;The application is safer&lt;/h3&gt;
&lt;p&gt;There&amp;#39;s no database, so no risk of SQL injection and other related vulnerabilities. If your blog
is attacked by some hacker, the biggest risk would be providing the markdown source of your
articles to the attacker. Basically, if you keep a back-up of your articles&amp;#39; repository, you&amp;#39;re
safe.&lt;/p&gt;
&lt;h3&gt;It&amp;#39;s simpler to setup&lt;/h3&gt;
&lt;p&gt;No need to create and tune any databases.&lt;/p&gt;
&lt;h3&gt;It&amp;#39;s very flexible / portable&lt;/h3&gt;
&lt;p&gt;You can easily move from LightBlog to something else in the future if you keep your articles separated from the application. Just create another application that can read your data (your
markdown-based article files).&lt;/p&gt;
&lt;h3&gt;Deploying is easy and the process is very lightweight&lt;/h3&gt;
&lt;p&gt;LightBlog requires very few resources. This site is hosted in a single e2-micro Compute Engine
instance at GCP at no cost at all (it&amp;#39;s within the free tier conditions). The e2-micro engine
provides very little CPU and RAM (1GB only) and yet it&amp;#39;s able to serve a blog with LightBlog very
easily.&lt;/p&gt;
&lt;h2&gt;Features&lt;/h2&gt;
&lt;p&gt;Out-of-the-box, LightBlog provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tagging support: group your articles by tags;&lt;/li&gt;
&lt;li&gt;atom feeds (for all articles and by tag too);&lt;/li&gt;
&lt;li&gt;optional comments provided by &lt;a href=&quot;https://disqus.com&quot;&gt;Disqus&lt;/a&gt; (just provide the Disqus forum/id in
the options);&lt;/li&gt;
&lt;li&gt;optional integration with Google Analytics (just provide the GA id in the options);&lt;/li&gt;
&lt;li&gt;optional automatic reloading of the articles;&lt;/li&gt;
&lt;li&gt;a rake task to generate a new empty article;&lt;/li&gt;
&lt;li&gt;a rake task to copy the default views (which can be overridden);&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;light_blog&lt;/code&gt; command to help you creating a new simple Rack application using LightBlog;&lt;/li&gt;
&lt;li&gt;internacionalization/localization support (integration with the i18n gem);&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gem install light_blog
light_blog new myblog
cd myblog
bin/rake article:new_article
# type in the article title
bin/puma -p 4000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then simply navigate to &lt;a href=&quot;https://localhost:4000&quot;&gt;https://localhost:4000&lt;/a&gt; to view your articles.&lt;/p&gt;
&lt;p&gt;Give it a try and let me know in the comments what you think about it.&lt;/p&gt;
</content:encoded></item><item><title>Thank you, Heroku!</title><link>https://rosenfeld.page/articles/2022_11_07_thank_you_heroku/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2022_11_07_thank_you_heroku/</guid><pubDate>Mon, 07 Nov 2022 21:40:00 GMT</pubDate><content:encoded>&lt;p&gt;For 13 years, I&amp;#39;ve hosted my articles on &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was a great experience. Not only Heroku was kind enough to offer free hosting for Ruby apps
all that time, but publishing a new article was only a &amp;quot;git push&amp;quot; operation. I haven&amp;#39;t experienced
a single problem in all those years.&lt;/p&gt;
&lt;p&gt;I think I talk on behalf of the Ruby Community when I say Heroku provided a very valuable resource
for Rubyists for all those years and it&amp;#39;s still a great platform for existing and new projects,
not only for Rubyists but for many other supported languages as well.&lt;/p&gt;
&lt;p&gt;On Nov 22th, 2022, however, Heroku is no longer providing a free plan, which is certainly
understandable.&lt;/p&gt;
&lt;p&gt;When I got communicated about this change, I also realized it would be a good idea to actually
use my own domain. Also, it has been some years since I last used Rails and my site was still
running in an older version of Rails, so I decided it would be a good idea to rewrite it in
&lt;a href=&quot;https://roda.jeremyevans.net/&quot;&gt;Roda&lt;/a&gt;, which is what I&amp;#39;ve been using for the past 4 years at least.&lt;/p&gt;
&lt;p&gt;Finally, I decided to test whether the e2-micro Google Cloud Platform compute engine type would be
enough for running my site. It&amp;#39;s very light, so I thought it would worth a try, since I can
currently run it for free using the Free Tier of Google Cloud Platform.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s how I moved the site to &lt;a href=&quot;https://rosenfeld.page&quot;&gt;https://rosenfeld.page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the process of rewriting my site, I thought it would be an opportunity to also open-source it.&lt;/p&gt;
&lt;p&gt;My site is currently split in 3 projects: a gem providing the main features, a Roda app that uses
this gem, and my articles in markdown format, which are saved in yet another repository.&lt;/p&gt;
&lt;p&gt;Right now all 3 repositories are private, but I intend to open-source the gem as soon as I finish
the remaining features I&amp;#39;d like to add besides adding some documentation. Then, I also intend to
open-source the Roda app that uses that gem at some point, although I don&amp;#39;t think most people
would be interested on this one. For the articles repository, I&amp;#39;m not planning to open-source it
for now since I think no one would actually benefit from it.&lt;/p&gt;
&lt;p&gt;If you find any issues on the new site, please report on the comments section.&lt;/p&gt;
&lt;p&gt;By the way, I&amp;#39;m not intending to import the Disqus discussions on my articles at Heroku.
The &lt;a href=&quot;https://rosenfeld.herokuapp.com&quot;&gt;old site&lt;/a&gt; is still available until Nov 29th, so feel free
to check any discussions there while it&amp;#39;s still possible.&lt;/p&gt;
&lt;p&gt;I also intend to remove some old articles soon, in the cases I think they would no longer be
relevant nowadays.&lt;/p&gt;
&lt;p&gt;Once again, thank you very much, Heroku, for all those years hosting my site.
I really appreciate it! &amp;lt;3&lt;/p&gt;
</content:encoded></item><item><title>Why proxying Bugsnag (or similar service) might be a good idea?</title><link>https://rosenfeld.page/articles/ruby-rails/2018_03_01_why_proxying_bugsnag_or_similar_service_might_be_a_good_idea/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2018_03_01_why_proxying_bugsnag_or_similar_service_might_be_a_good_idea/</guid><pubDate>Thu, 01 Mar 2018 19:45:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.bugsnag.com/&quot;&gt;Bugsnag&lt;/a&gt; is a great error monitoring service that takes care of
reporting and filtering/notifying exceptions in several kind of applications. I used to use
my own error reporting tool in the app I currently maintain but as I&amp;#39;m currently evaluating
creating a new application, I started to evaluate Bugsnag to save me some time. But I stumbled
upon an issue I didn&amp;#39;t have to deal with my custom error reporting tool.&lt;/p&gt;
&lt;p&gt;When reporting errors, it&amp;#39;s a good idea to attach as much meaningful data as they could be
quite helpful when trying to understand some errors, specially when they aren&amp;#39;t easily
reproducible. Such data include user information which I&amp;#39;d prefer not to expose to the front-end,
including the user id.&lt;/p&gt;
&lt;p&gt;I was initially worried about exposing the API key to the front-end, which someone could use to
report errors to my account, but then I figured out I was being too paranoid and that proxying
the request wouldn&amp;#39;t prevent users from reporting errors to my account, unless I&amp;#39;d implement
some sort of rate limit protection or disabling errors reporting for non authenticated users
(after all, I&amp;#39;d be able to track authenticated users acting that way and take some action
against them).&lt;/p&gt;
&lt;p&gt;However, hiding from the front-end user data meant to be used only internally is important to me.
That&amp;#39;s why I decided to take a few hours to proxy browsers errors through the back-end. Here&amp;#39;s
how it was implemented using the official &lt;em&gt;bugsnag-js&lt;/em&gt; npm package and the &lt;em&gt;bugsnag&lt;/em&gt; Ruby gem.&lt;/p&gt;
&lt;p&gt;In the JavaScript code, there&amp;#39;s something like showed below. I used XMLHttpRequest rather than
&lt;em&gt;fetch&lt;/em&gt; in order to support IE11 since the polyfills are lazy loaded as required in our application
and fetch may not be available when Bugsnag is initialized in the client:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import bugsnag from &amp;#39;bugsnag-js&amp;#39;;
const bugsnagClient = bugsnag({
  apiKey: &amp;#39;000000000000000000000000&amp;#39;, // the actual api key will be inserted in the back-end
  beforeSend: report =&amp;gt; {
    const original = report.toJSON(), event = {};
    let v;
    for (let k in original) if ((v = original[k]) !== undefined) event[k] = v;
    report.ignore();

    const csrf = (document.querySelector(&amp;#39;meta[name=_csrf]&amp;#39;) || {}).content;
    const xhr = new XMLHttpRequest();
    xhr.open(&amp;#39;POST&amp;#39;, &amp;#39;/errors/bugsnag-js/notify?_csrf=&amp;#39; + csrf);
    xhr.setRequestHeader(&amp;#39;Content-type&amp;#39;, &amp;#39;application/json&amp;#39;);
    xhr.send(JSON.stringify(event));
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The back-end is a Ruby application built on top of the &lt;a href=&quot;http://roda.jeremyevans.net/&quot;&gt;Roda toolkit&lt;/a&gt;.
It uses the &lt;a href=&quot;http://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/MultiRun.html&quot;&gt;multi_run&lt;/a&gt;
plugin, splitting the main applications into multiple apps (which can be seen as powerful
controllers if it helps understanding how it works). These are the relevant parts of the back-end:&lt;/p&gt;
&lt;p&gt;lib/setup_bugsnag.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# frozen-string-literal: true

require &amp;#39;app_settings&amp;#39;
require_relative &amp;#39;../app_root&amp;#39;

if api_key = AppSettings.bugsnag_api_key
  require &amp;#39;bugsnag&amp;#39;

  Bugsnag.configure do |config|
    config.api_key = AppSettings.bugsnag_api_key
    config.project_root = APP_ROOT
    config.delivery_method = :synchronous
    config.logger = AppSettings.loggers
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;app/apps/errors_app.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# frozen-string-literal: true

require &amp;#39;json&amp;#39;
require_relative &amp;#39;base_app&amp;#39;
require &amp;#39;bugsnag_setup&amp;#39;

module Apps
  class ErrorsApp &amp;lt; BaseApp
    private

    def process(r)
      super
      r.post(&amp;#39;bugsnag-js/notify&amp;#39;){ notify_bugsnag }
    end

    def notify_bugsnag
      api_key = settings.bugsnag_api_key
      head :ok unless api_key &amp;amp;&amp;amp; settings.store_front_end_errors
      event = JSON.parse request.body.read
      user_data = auth_session.to_h
      user_data[&amp;#39;id&amp;#39;] = user_data[&amp;#39;profile_id&amp;#39;]
      event[&amp;#39;user&amp;#39;] = user_data
      event[&amp;#39;apiKey&amp;#39;] = api_key
      event[&amp;#39;appVersion&amp;#39;] = settings.app_version
      payload = { apiKey: api_key, notifier: {
        name: &amp;#39;Bugsnag JavaScript&amp;#39;, version: &amp;#39;4.3.0&amp;#39;, url: &amp;#39;https://github.com/bugsnag/bugsnag-js&amp;#39;
      }, events: [event] }
      configuration = Bugsnag.configuration
      options = {
        headers: {
          &amp;#39;Bugsnag-Api-Key&amp;#39; =&amp;gt; api_key,
          &amp;#39;Bugsnag-Payload-Version&amp;#39; =&amp;gt; event[&amp;#39;payloadVersion&amp;#39;],
        }
      }
      Bugsnag::Delivery[configuration.delivery_method].
        deliver(configuration.endpoint, JSON.unparse(payload), configuration, options)

      &amp;#39;OK&amp;#39; # optional response body, could be empty as well, we don&amp;#39;t check the response
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s it, some extra code, but it allows me to send useful information to Bugsnag while not
requiring us to expose them to the front-end application. Hopefully next time I need something
like that it will help to have it written down here ;)&lt;/p&gt;
</content:encoded></item><item><title>The missing bit in the React community: a common interface</title><link>https://rosenfeld.page/articles/front-end/2018_01_25_the_missing_bit_in_the_react_community_a_common_interface/</link><guid isPermaLink="true">https://rosenfeld.page/articles/front-end/2018_01_25_the_missing_bit_in_the_react_community_a_common_interface/</guid><pubDate>Thu, 25 Jan 2018 17:52:00 GMT</pubDate><content:encoded>&lt;p&gt;I use Ruby for server-side programming, so I&amp;#39;ll illustrate the issue in the Ruby community but
it basically applies to all server-side languages. Even JavaScript I&amp;#39;d guess, although I haven&amp;#39;t
used JavaScript for server-side programming yet.&lt;/p&gt;
&lt;p&gt;When it&amp;#39;s time to deploy our Ruby web application, we&amp;#39;re free to choose a web server from multiple
options without requiring any changes to the application code most of the time. That&amp;#39;s possible
because all of them support the Rack specifications, which acts like an interface between Ruby
apps and Rack web servers. When we choose a process-based server such as Unicorn, we can benefit
from several advantages over thread-based ones, such as Puma, but the opposite is just as true,
since a thread-based approach also has benefits over a process-based one. Other web servers are
more suited to applications requiring long-live connections and would take yet another approach
to connections handling.&lt;/p&gt;
&lt;p&gt;The simple fact that we can easily switch the web server without changing our code to test the
impact of different in our application is awesome, but Rack will also make it easier for new
Ruby frameworks to be built and inter-operate with each other pretty easily. For example, you
can mount Rodauth, which is a Roda authentication app, in a Rails or Sinatra app in a very
straightforward way.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s not really news that competition is awesome for consumers, and we, software developers,
are consumers of libraries and frameworks, so we really enjoy competition of frameworks and
libraries, right?&lt;/p&gt;
&lt;p&gt;So, how could that be related to React in any way? After all, one might argue that React is
competing with Angular, jQuery and others, right? Well, in that sense, competition still
exists in the JavaScript framework/library market, but that&amp;#39;s just not enough. I&amp;#39;ll explain.&lt;/p&gt;
&lt;h2&gt;The Components problem&lt;/h2&gt;
&lt;p&gt;The way we build and use components are the biggest issue we currently experience in the
JavaScript world. For example, the Material UI library doesn&amp;#39;t compete with ng-bootstrap,
for example. How could them? The components interface are completely different in React
apps when compared to Angular apps. In that sense, we could consider React and Angular as
two different languages. One wouldn&amp;#39;t expect to be able to use the Ruby&amp;#39;s Rack gem in the
Go language, right?&lt;/p&gt;
&lt;p&gt;So, yes, it leads to duplicate efforts to build great common components such as date pickers,
sliders and so on. We have jQuery UI for jQuery, ng-bootstrap for Angular and Material UI for
React (among many more options for sure). But it kind of makes sense to me that components
implementation could be quite different because jQuery, Angular and React take completely
different approaches. One might argue that we could concentrate the efforts on pure JavaScript
solutions and build wrappers around it for each major library, such as React, Angular or jQuery.
But I don&amp;#39;t really think it would be that simple, so I&amp;#39;m not trying to suggest something like that.&lt;/p&gt;
&lt;p&gt;When one creates a new programming language, it will take quite some time before it gets widely
adopted. One of the reasons is that there&amp;#39;s no ecosystem around that language initially. When
Elixir was created, for example, there was no web framework available for it, of course. Ruby
not only has a lot of choices for web frameworks but also offer several libraries for all sort
of things you might need. Or Java. Or JavaScript, C++, whatever. Well stablished languages will
take advantage over new ones exactly because of this existing libraries, making it hard for
new languages to get traction. Unfortunately, I don&amp;#39;t think there&amp;#39;s something we could do to
make it easier for new languages to be created and take advantage of existing libraries from
other languages. But, fortunately, the React issue is much simpler to fix, if the community
wants to.&lt;/p&gt;
&lt;h2&gt;What is different in React?&lt;/h2&gt;
&lt;p&gt;When React was born, it was really a game changer.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m not saying everyone should be leaving jQuery or Angular or whatever to jump to the React boat.
There&amp;#39;s no one-size-fits-all solution for creating applications. Angular, jQuery and React take
completely different approaches when creating applications. Angular 1 has tried two-way data
binding but gave up on it since version 2. Both Knockout.js and Vue.js still support two-way data
binding. There are plenty of people that enjoy that feature. And for some use cases, it&amp;#39;s
certainly quicker to build some use cases with it when compared to newer Angular or React.&lt;/p&gt;
&lt;p&gt;However, it&amp;#39;s clear to me that React got way more traction than its competitors in the past few
years. And there are plenty of reasons for that. I really think React did a great job in teaching
us a new way to think about applications. It&amp;#39;s not a secret that programming is mostly complicated
because of state management, right? I still prefer OO programming over functional one, but I do
agree with the most used argument from functional programming fans: managing state is hard. They
claim functional programming is easier because it&amp;#39;s easy to understand and test pure functions.
It&amp;#39;s the same sort of argument used by supporters of micro-services that will tell us that it&amp;#39;s
much easier to write and test micro apps than a big monolithic one.&lt;/p&gt;
&lt;p&gt;And their arguments are not wrong. Just incomplete from my point of view. Because they hide the
fact that they have moved the complexity to the integration part. By the way, it&amp;#39;s perfectly
possible to create modular monolithic applications whose parts can be tested and released
independently while keeping the integration much simpler than with micro-services. I&amp;#39;m not saying
one should never adopt the micro-services approach either. There&amp;#39;s no silver bullet. The
complexity will always exist somewhere and our job is to see what makes more sense for our project.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#39;ll not get into this discussion in this article, but just want to highlight that the
most complicated part when creating applications is state management. Truth be told, trying to
keep your model and view in sync using jQuery has always been a nightmare, right? That&amp;#39;s why we
see several alternatives to jQuery for many reasons, like Knockout.js, Angular and many others.
The main difference between them and jQuery is that they will let us manage the state outside of
the DOM and will make sure that the DOM will change accordingly to the app&amp;#39;s state. That&amp;#39;s a big
win over jQuery or any other DOM-based library.&lt;/p&gt;
&lt;p&gt;So, why did React get much more traction than the alternatives? In my opinion, React is much
simpler than the alternatives, while remaining flexible and fast. For example, Knockout.js,
initial versions of Ember (I&amp;#39;m not following the current development, so I can&amp;#39;t talk about recent
versions) and Angular would all try to extend the HTML in sophisticated ways. They have to parse
either the HTML template itself or some special tag properties and evaluate some special
constructions. Knockout, for instance, would evaluate &amp;quot;data-bind&amp;quot; attributes, which resembles
very closely a JavaScript object declaration. Both Ember and Angular would also offer their
own control flow extensions instead of using plain JavaScript, because they preferred declarative
(logic-less) templates. Maybe that description is not fully accurate as I never worked with
Angular or Ember, but this is what I remember from the articles I&amp;#39;ve read back in those days.&lt;/p&gt;
&lt;p&gt;React took a completely different approach, making the JavaScript developer life much simpler in
several ways. At first, I (and many others) were scared by the JSX thing, when it seemed an
heresy to embed HTML in the JavaScript, bringing memories from PHP and ASP to the mind. However,
I (and many others) realized that it actually made sense. After all, I often ended up doing that
myself in several cases using other methods. It might seem scaring at first, but quickly we
get used to it and it makes sense. We&amp;#39;ll even mix CSS and JS these days (also known as CSS in JS).&lt;/p&gt;
&lt;p&gt;But JSX wasn&amp;#39;t the main reason why people adopted React. I guess there are many people who
actually adopted React despite the JSX thing, rather than because of it. There are two key
ideas that set React apart and were responsible for its success in my opinion. And I&amp;#39;m not
talking about documentation or component-driven programming because the alternatives also offered
those.&lt;/p&gt;
&lt;p&gt;One of them is the realization that keeping the model and view in sync is the major issue to be
fixed by library authors. Approaches taken by Knockout, Angular and Ember seemed too complicated.
Trying to figure out what has to be changed in the view when the application state changed was
really tricky. Then, React decided to try a much simpler approach. What if we just rebuilt the
entire app from scratch after any changes to the application? Well, of course the alternative
frameworks could also implement that brilliant idea that simplifies a lot the implementation.
Except that it would be painfully slow to do that.&lt;/p&gt;
&lt;p&gt;So, that&amp;#39;s the second idea, which allowed the first one to succeed, was the key for the revolution
we&amp;#39;ve seen in the JavaScript scenario after React was born. The realization that JavaScript is
pretty fast nowadays, as long as we can avoid the DOM, which is the slow part. And that&amp;#39;s how
the concept of virtual DOM became popular and today we have tons of alternative virtual DOM
implementations. The realization that comparing an in-memory DOM was really fast allowed a
not too complicated algorithm to update the DOM in a very efficient way to reflect the state of the
virtual DOM. Of course, there are much more optimizations applied by React and similar
alternatives, but the implementation of the virtual DOM diff algorithm allowed developers to
quickly understand how to build React apps. It was much simpler to reason about than the
alternatives, in my opinion.&lt;/p&gt;
&lt;p&gt;And to make things even better, they adopted modern JavaScript, which allowed us to write
Object Oriented programming in JavaScript without having to resort to CoffeeScript and
alternative transpiled languages. When we add bundle builders as sophisticated as Webpack,
things get quickly unbeatable. Now we&amp;#39;re able to write modular conflict-less apps, using
OO component-based programming, with an easy syntax to mix HTML in JavaScript. We can even
even import CSS from JS or apply code splitting with Webpack. Or use some of the CSS in JS
alternatives, such as JSS. But, again, the biggest gain is that we no longer need to touch
the DOM directly, without having to learn a new template syntax. We just use plain JavaScript.&lt;/p&gt;
&lt;h2&gt;React is awesome, I know, so what is the issue after all?&lt;/h2&gt;
&lt;p&gt;The issue is that React is not just an implementation. It&amp;#39;s a powerful idea and mind set. The
concepts are so simple, that we now have many alternative to React which are mostly compatible
with it. There are Dio.js, Inferno.js, Preact and NervJS to name some well known alternatives.
Each of them could be competing with each other but unfortunately it&amp;#39;s not that simple.&lt;/p&gt;
&lt;p&gt;Why is that? Because you can&amp;#39;t simply use some UI library designed to work with React in any
of the alternatives. For one to be able to do that, they would have to use something like
Webpack aliases, so that whenever the code imports &amp;#39;react&amp;#39;, &amp;#39;react-dom&amp;#39; or &amp;#39;create-react-class&amp;#39;
they would be actually importing some compatibility layer around the alternatives. Something
like &amp;#39;inferno-compat&amp;#39;. What if we wanted to mix apps which are lazily loaded but developed by
separate teams? Maybe one team is using React for a reason, while another team is using Inferno
or Dio.js for another reason. Then the webpack rules get way more complicated to manage.&lt;/p&gt;
&lt;p&gt;What if we could set up a common interface supported by all react-like implementations.
Something like Ruby&amp;#39;s Rack but for React components? UI libraries are basically React components.
Basically they rely on JSX (not all of them, though) and React.Component. Both interfaces are
very well known. JSX is already independent from React, but it still needs to know which pragma to
use when parsing JSX. When using Babel, one can easily add a plugin that will include
additional imports automatically so that you shouldn&amp;#39;t be forced to &amp;quot;import React&amp;quot; in order to use
JSX. But it would be great if we didn&amp;#39;t have to resort to such things when targeting
interoperability.&lt;/p&gt;
&lt;p&gt;For React like programming I believe there&amp;#39;s a fixed set of methods that should be enough for
most apps. Functions such as like createElement (for JSX support, also known as &amp;quot;h&amp;quot; by some
implementations), render, Component, createPortal and findDOMNode. What if we could create a meta
package to provide us such method? Then all React-like alternatives could compete with each other
by providing the implementation for such functions.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s suppose we create a new &amp;quot;react-like&amp;quot; package. We could set up which library
to use like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import ReactLike from &amp;#39;react-like&amp;#39;;
import dio from &amp;#39;dio.js&amp;#39;;
ReactLike.assign(dio); // or assign({createElement: dio.createElement, createPortal: dio.createPortal ...})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, instead of &amp;quot;import React from &amp;#39;react&amp;#39;&amp;quot;, component libraries, such as Material UI, could use
it like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import React from &amp;#39;react-like&amp;#39;;

export default Button extends React.Component {
  render() {
    return &amp;lt;button className=&amp;quot;my-special-class&amp;quot;&amp;gt;{ this.props.children }&amp;lt;/button&amp;gt;;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It would be even better if those libraries used yet another abstraction with a fallback to
&amp;#39;react-like&amp;#39;, so that we would be able to use Inferno for some library and Dio.js for another one,
for example.&lt;/p&gt;
&lt;p&gt;Currently it&amp;#39;s not an easy for us to pick up one of the great React alternatives out there because
almost all component libraries seem to assume React is being used. Wouldn&amp;#39;t it be awesome if
we could provide a common interface to be used by components libraries and promote the competition
among React alternatives?&lt;/p&gt;
</content:encoded></item><item><title>Introducing sequel_tools: Rake integration over Sequel migrations and related tasks</title><link>https://rosenfeld.page/articles/ruby-rails/2017_12_15_introducing_sequel_tools_rake_integration_over_sequel_migrations_and_related_tasks/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2017_12_15_introducing_sequel_tools_rake_integration_over_sequel_migrations_and_related_tasks/</guid><pubDate>Fri, 15 Dec 2017 12:30:00 GMT</pubDate><content:encoded>&lt;h2&gt;The importance of the little details (skip this section unless you enjoy rants)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Seriously, this section is big and not important at all, feel free to completely skip it right now
if you&amp;#39;re short in time or don&amp;#39;t enjoy rants.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a rant explaining how ActiveRecord migrations completely defined my career in the past
years.&lt;/p&gt;
&lt;p&gt;I became curious about programming and computers when I was kid. I remember reading a huge C++
book when I was about 10 years old. I had learned Clipper just a bit before and I recall creating
a Bingo game with Clipper, just because I wanted to play Bingo in those machines but I couldn&amp;#39;t :)
While learning Clipper I also had my first experience learning SQL and client-server design.
My dad subscribed me to a few computer courses by that time, such as &amp;quot;DOS/dBase III Plus&amp;quot;,
Clipper + SQL and a few years later Delphi + Advanced SQL. I learned C and C++ from books and
when services like Geocities and similar were showing up and the Internet was becoming supported
in lots of homes I also became interested in learning HTML to build my own sites, the new hotness
for that time. Since I also wanted to serve dynamic content, I decided to learn Perl since it was
possible to find some free hosting services supporting Perl, and that was the first interpreted
language I learned and I was really fascinated by it by that time.&lt;/p&gt;
&lt;p&gt;For a long while I used Perl exclusively for server-side web programming since it was the only
option I could find in free hosting services, but while in Electrical Engineering college,
I barely did any web programming, and my programming tasks (extra classes) were mostly related
to desktop programming (Delphi / C++) and embedded and hard real-time systems using a mix of
C and C++ during my master thesis in Mobile Robotics. By that time I had a solid understanding
of C and C++, good times, I don&amp;#39;t find myself proficient with them anymore these days. That was
a time where I would read and know the entire specs from W3C or HTML 4.01 and CSS. Today it&amp;#39;s
simply unfeasible to completely follow all related specs and I&amp;#39;m glad we have competition in
the browser&amp;#39;s marketing since it&amp;#39;s really hard to follow up with all changes happening every day.&lt;/p&gt;
&lt;p&gt;Once I finished my master thesis and had to find a job, I looked mostly for programming jobs,
since I considered myself good in programming, there were lots of interesting opportunities out
there while it was really hard to find companies in Brazil working on electronic devices
development or Robotics and I never actually enjoyed the other part of Electrical Engineering
such as machines, power or electrical installations. I only enjoyed the micro-electronics
and embedded devices creation and one should consider themselves very lucky if they can work in
such area in Brazil, and I didn&amp;#39;t want to count on luck, so I decided to focus on the programming
career instead. I remember my first curriculum was sent to Opera Software, my preferred browser,
to apply to a C++ developer position, by that time, but after tons of interviews they didn&amp;#39;t call
me, so I&amp;#39;m not currently living in Norway these days ;)&lt;/p&gt;
&lt;p&gt;After working for 3 months in a new parking system using Delphi (despite asking for using C++
instead) the contract was finished, the product was already working in one of the malls in my city,
and I had to look for another job. They actually extended the offer to keep working with them,
but at the same time I found another opportunity and this time I would have to get back to web
programming. That was in 2007. Several years later and I couldn&amp;#39;t really remember much of Perl
and a lot had happened to web programming in the past years and I didn&amp;#39;t follow that progress.&lt;/p&gt;
&lt;p&gt;After a few stressful days trying to learn about every major web programming framework (specially
while trying to read about J2EE), I came to the conclusion that I would finally choose one of
TurboGears, Django or Rails. I didn&amp;#39;t know Java, Python or Ruby by that time, so the language
didn&amp;#39;t take an important role while choosing the framework. I was more interested in learning
about how the frameworks would make my life easier. At that time I had to maintain an existing
ASP application but at some point I would have to create a new application and I could choose
whatever I wanted and definitely I didn&amp;#39;t enjoy ASP.&lt;/p&gt;
&lt;p&gt;Since that application had to be displayed in Portuguese, I was considering the Python frameworks
more than the Ruby one, as Rails didn&amp;#39;t support internationalization by that time (i18n support
was added to Rails 2 if I recall correctly) and even supporting UTF-8 wasn&amp;#39;t straightforward with
Ruby 1.8. Iconv and $KCODE were something you&amp;#39;d often hear about in the Ruby community by that
time. There were tons of posts dedicated to encoding in Ruby by that time.&lt;/p&gt;
&lt;p&gt;But there was that one Rails feature that made me change my mind and choose Rails over TurboGears
or Django, which were supposed to work well with encodings and had announced internationalization
support. And it was the approach used to evolve databases, which was the right strategy to use
from my previous experiences, while I was pretty scared by the model-centered approaches used
by TurboGears and Django to handle the database evolution.&lt;/p&gt;
&lt;p&gt;By that time I had already plenty of experience working with RDBMS, specially Firebird, and having
to deal with versioning the database and supporting multiple environments. That took me a lot of
effort every time I started a new project because I basically had to implement the ActiveRecord
migrations features every time and I knew that was very time consuming, so I was glad I wouldn&amp;#39;t
have to roll my own solution if I used Rails, as ActiveRecord migrations were clearly more than
enough for my needs and they worked pretty well. So, despite the issues with encoding and lack
of internationalization support, I decided to pick Rails due to the ActiveRecord migrations.&lt;/p&gt;
&lt;p&gt;And even though I don&amp;#39;t use ActiveRecord for several years, I&amp;#39;ve been still using its migrations
tools since 2007, more recently through my wrapper around it called
&lt;a href=&quot;https://github.com/rosenfeld/active_record_migrations&quot;&gt;active_record_migrations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I don&amp;#39;t appreciate ActiveRecord as an ORM solution, I like its migrations tooling very much
and they haven&amp;#39;t changed much since I used them with Rails 1. The most significant changes since
then were support for time-stamped migrations, the reversible block and finally, many years later,
proper support for foreign keys (I struggled to add foreign keys using plain SQL for many years).&lt;/p&gt;
&lt;p&gt;When I first read about Sequel I was fascinated by it. ActiveRecord wasn&amp;#39;t built around Arel yet
by that time, so all those lazy evaluations in Sequel were very appealing to me. But around 2009
I took another job opportunity and this time I would work with Grails and Java rather than Rails,
so I missed many recent changes to Rails for a while. In 2011 I changed my job again, but still
had to support a Grails application, but I was free to do whatever I liked to the project and
since there were quite a lot of Grails bugs that were never fixed and I couldn&amp;#39;t find work-arounds
for, I decided to slowly migrate the Grails app to Rails. By that time, Arel had been integrated
to ActiveRecord, so it would finally support lazy evaluation as well, so I decided to try to
stick with Rails defaults, but a week later I realized that there were still many more reasons
why Sequel was far superior to ActiveRecord and decided to replace ActiveRecord with Sequel and
never looked back. Best decision ever.&lt;/p&gt;
&lt;p&gt;See, I&amp;#39;m a database guy. I work with the database, not against it. I don&amp;#39;t feel the need to
abstract the database because I&amp;#39;d prefer to use Ruby over SQL. I was able to appreciate not only
SQL but several other powerful tools provided by good database vendors, such as triggers, CTE,
stored procedures, constraints, transactions, functions, foreign keys and definitely I didn&amp;#39;t
want to avoid the database features at all. ActiveRecord seems to try to focus on hiding the
database from the application, by trying to abstract as much as possible so that you feel you&amp;#39;re
just working with objects. That&amp;#39;s probably the main reason why I loved Sequel. Sequel embraced the
database, it didn&amp;#39;t fight the database. It would try to make it as easy as possible to use whatever
vendor-specific feature I wanted to, without getting in my way. That&amp;#39;s why I don&amp;#39;t see Sequel
as an ORM, but as a tool that allows me to write the SQL I want with a level of control and logic
that would be pretty hard to achieve by building SQL queries through concatenation techniques and
manual typecasting of params and result sets.&lt;/p&gt;
&lt;p&gt;I can always have a clear idea on the SQL generated by Sequel and it&amp;#39;s way more readable than if
I had to write the SQL by hand myself.&lt;/p&gt;
&lt;p&gt;When I first learned about Sequel, Jeremy Evans was already its maintainer, but it seems Sequel
was first created by Sharon Rosner. Recently I read this
&lt;a href=&quot;http://korban.net/posts/postgres/2017-11-02-the-case-against-orms/&quot;&gt;article&lt;/a&gt;, where this quote
came to my attention:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&amp;#39;m the original author of Sequel [1], an ORM for Ruby. Lately I&amp;#39;ve been finding that ORM&amp;#39;s actually get in the way of accomplishing stuff. I think there&amp;#39;s a case to be made for less abstraction in programming in general, and access to data stores is a major part of that. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;For an in-production system I&amp;#39;ve been maintaining for the last 10 years, I&amp;#39;ve recently ripped out the ORM code, replacing it with raw SQL queries, and a bit of DRY glue code. Results: less code, better performing queries, and less dependencies. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Sharon Rosner, Sequel original author&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Good that it&amp;#39;s working well for him, but I really find it weird to see that he would consider
Sequel a traditional ORM. To me, Sequel allows me to write more maintainable queries, so I
consider it more of a query builder than an ORM. If I had to build all SQL by hand and typecast
params and result sets by hand, I think the result would be much worse, not better.&lt;/p&gt;
&lt;p&gt;So, nowadays, I&amp;#39;m considering creating a brand new application after several years, and I&amp;#39;m
frustrated that it takes a really long time to bootstrap a production-ready new application with
the state-of-the-art features. I started working on such sample project to serve as a start point.
The idea is to add features such as automated deployment, including blue-green (canary) strategies
for zero downtime, using Roda as the Ruby framework, Webpack to bundle static resources, support
a lightweight alternative to React, such as Dio.js or Inferno.js, supporting multiple environments,
flexible configurations, client-side routing, proper security measures (CSRF, CSP headers),
a proper authentication system, such as Rodauth, proper images uploading (think of Shrine),
distributed logging (think of fluentd) with proper details, reliable background jobs, server-side
and client-side testing, support for lazy code loading for both client-side and server-side,
autoreloading of Ruby code in the server-side, analytics, APM, client-side performance tricks such
as link preloading, performance tracking for both server-side and client-side code, errors
tracking for both server-side and client-side code, integrated with sourcemaps and notifications
from monitoring services, CDN support, full-text search through ElasticSearch or Solr, caching
storage such as Redis, Docker based infra-structure, backup, high-availability of databases,
and many many more features that are supposed to be found in production-ready applications.
As you can see, it&amp;#39;s really frustrating to create a new application from scratch these days,
as it seems any new product could easily take an year to reach a solid production-ready level.
And, of course, support for database migrations.&lt;/p&gt;
&lt;p&gt;The last thing I would want to worry about while working on this huge project is to waste time
with a simple task, such as managing the database state through some migrations and related tools.
Specially as ActiveRecord migrations have been providing that for so long and it works pretty well.
However, this time I really wanted to ditch the dependency on railties for this new project, and
active_record_migrations relies on railties for simplicity, so that it can take advantage of the
Rails generators and just be a very simple wrapper around ActiveRecord migrations. But since
AR itself won&amp;#39;t be used in this project, I decided to spend several hours (about two full days),
replicating the most important tools from ActiveRecord to Sequel. And this is how
sequel_tools was born this week.&lt;/p&gt;
&lt;p&gt;I find it interesting how such a little detail, like Rails bundling a proper database migrations
tooling, influenced a lot of my career, since I only learned Ruby because of Rails in the first
place and I only chose Rails because of ActiveRecord migrations :) If I was working with Python
I wouldn&amp;#39;t have learned Ruby most likely and wouldn&amp;#39;t work in my current job, and wouldn&amp;#39;t have
created many gems such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/rosenfeld/active_record_migrations&quot;&gt;active_record_migrations&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/auto_reloader&quot;&gt;auto_reloader&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rack_web_console&quot;&gt;rails-web-console&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ontohub/sequel-devise&quot;&gt;sequel-devise&lt;/a&gt; (no longer maintained by me);&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rspec_nested_transactions&quot;&gt;rspec_nested_transactions&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rails_compatible_cookies_utils&quot;&gt;rails_compatible_cookies_utils&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rails-web-console&quot;&gt;rack_web_console&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/hotkeys-manager&quot;&gt;global_hotkeys_manager&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rack_toolkit&quot;&gt;rack_toolkit&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/simple_mail_builder&quot;&gt;simple_mail_builder&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;and now &lt;a href=&quot;https://github.com/rosenfeld/sequel_tools&quot;&gt;sequel_tools&lt;/a&gt;, among others.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#39;ve also been using Ruby for some other projects such as
&lt;a href=&quot;https://github.com/rosenfeld/cert-generator&quot;&gt;cert-generator&lt;/a&gt;, a Rack application that can be
launched from a Docker container that allows development suited auto-signed root CA and HTTPS
certificates in such a way supported by modern browsers. &lt;a href=&quot;/en/articles/programming/2017-12-01-testing-https-in-a-linux-development-environment-with-self-signed-certificates&quot;&gt;I&amp;#39;ve written about it in my previous
article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Or I wouldn&amp;#39;t have contributed to some Ruby projects such as Rails, orm_adapter-sequel, Redmine,
Gitorious (now dead), Unicorn, RSpec-rails, RSpec, Capistrano, Sequel, js-routes, jbundler,
database_cleaner, Devise, ChiliProject, RVM, rails-i18n, rb-readline and acl9. Most of them were
minor contributions or documentation updates, but anyway... :)&lt;/p&gt;
&lt;p&gt;Not to mention many bugs reported to MRI, JRuby and Ruby projects that have been fixed since then.
And, before I forget, some features have been added to Ruby after Matz approved some of my
requests. For example, the soon to be released &lt;a href=&quot;https://blog.jetbrains.com/ruby/2017/10/10-new-features-in-ruby-2-5/&quot;&gt;Ruby 2.5 is introducing ERB#result_with_hash&lt;/a&gt;
(&lt;a href=&quot;https://bugs.ruby-lang.org/issues/8631&quot;&gt;see issue #8631&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Or my request to &lt;a href=&quot;https://bugs.ruby-lang.org/issues/6265&quot;&gt;remove the &amp;#39;useless&amp;#39; &amp;#39;contatenation&amp;#39; syntax&lt;/a&gt;
that was approved by Matz about 5 years ago, and I still hope someone would implement it at some
point :)&lt;/p&gt;
&lt;p&gt;I wonder what would be my current situation if ActiveRecord migrations weren&amp;#39;t bundled with Rails
in 2007 :) On the other side, maybe I could have become rich working with Python? ;)&lt;/p&gt;
&lt;h2&gt;Introducing sequel_tools&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;re a Sequel user, you probably spent a while searching for Rake integration around Sequel
migrations and realized it was more time than you&amp;#39;d wished. I&amp;#39;ve been in the same situation, but
it was so frustrating to me, because I wasn&amp;#39;t able to find all tasks I want to have at disposal,
that I&amp;#39;d often just forget about using Sequel migrations to stick with ActiveRecord migrations.
Not because I like the AR migrations DSL better (I don&amp;#39;t by the way), but because all tooling is
already there, ready to be used through some simple rake commands.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rosenfeld/sequel_tools&quot;&gt;sequel_tools&lt;/a&gt; is my effort in trying to come up with
some de facto solution for integrating Sequel migrations and related tooling and Rake, and see
if the Sequel community could concentrate the efforts on building together a solid foundation for
Sequel migrations. I hope others would sympathize and contribute to the goal, so that we wouldn&amp;#39;t
have to waste time thinking about migrations again in the future when using Sequel.&lt;/p&gt;
&lt;p&gt;Here are some of the supported actions, which can be easily integrated to Rake, but are implemented
in such a way that other interfaces, such as command lines or Thor, should be also made easy to
build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create the database;&lt;/li&gt;
&lt;li&gt;drop the database;&lt;/li&gt;
&lt;li&gt;migrate (optionally to a given version, or latest if not informed);&lt;/li&gt;
&lt;li&gt;generate a migration file (time-stamp based only);&lt;/li&gt;
&lt;li&gt;status (which migrations are applied but missing locally and which are not yet applied to the
database);&lt;/li&gt;
&lt;li&gt;version (show current version / last applied migration);&lt;/li&gt;
&lt;li&gt;rollback last applied migration which is present in the migrations path;&lt;/li&gt;
&lt;li&gt;run a given migration up block if it hasn&amp;#39;t been applied yet;&lt;/li&gt;
&lt;li&gt;run a given migration down block if it hasn&amp;#39;t been applied yet;&lt;/li&gt;
&lt;li&gt;redo: runs a given migration down and up, which is useful when writing some complex migrations;&lt;/li&gt;
&lt;li&gt;dump schema to schema.sql (configurable, can happen automatically upon migration - implemented
just for PostgreSQL for now, by calling pg_dump, but should be easy to extend to support other
databases: PRs are welcomed or additional gems);&lt;/li&gt;
&lt;li&gt;load from schema;&lt;/li&gt;
&lt;li&gt;support for seeds.rb;&lt;/li&gt;
&lt;li&gt;reset by re-running all migrations over a new database and running the seeds if available;&lt;/li&gt;
&lt;li&gt;setup by loading the saved schema dump in a new database and running the seeds if available;&lt;/li&gt;
&lt;li&gt;execute a sql console through the &amp;quot;shell&amp;quot; action;&lt;/li&gt;
&lt;li&gt;execute an irb console through the &amp;quot;irb&amp;quot; action. This works like calling &amp;quot;bundle exec sequel connection_uri&amp;quot;. The connection is stored in the DB constant in the irb session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I decided not to support the Integer based migrations at this point as I can&amp;#39;t see any drawbacks
of time-stamp based migrations that would be addressed by the Integer strategy while there are
many problems with the Integer strategy even if there&amp;#39;s a single developer working in the project.
I&amp;#39;m open to discuss this with anyone that thinks that could convince me otherwise that supporting
Integer based migrations would add something to the table. It&amp;#39;s just that it&amp;#39;s more code to
maintain and test and I&amp;#39;m not willing to do that unless there is indeed some advantage over
using time-stamp based migrations.&lt;/p&gt;
&lt;p&gt;The project also allows missing migration files, since I find it useful specially when reviewing
multiple branches, dealing with independent migrations.&lt;/p&gt;
&lt;p&gt;I don&amp;#39;t think it&amp;#39;s a good idea to work with a Ruby format for storing the current schema, as a
lot of things are specific to the database vendor. I never used the Ruby vendor-independent format
in all those years, but if you think you&amp;#39;d value such a feature in case you just use the basics
when designing the tables and want your project to support multiple database vendors, then go
ahead and either send a Pull Request to make it configurable, or create an additional gem to add
that feature and I can link to it in the documentation.&lt;/p&gt;
&lt;p&gt;I&amp;#39;d love to get some feedback regarding what the Sequel community would think about it. I&amp;#39;d love
for us to get to some consensus on what should be the de facto solution for managing Sequel
migrations in a somewhat feature-complete fashion and would love to get the community help on
making such de facto solution happen to the best interest of we, Sequel happy (and sometimes
frustrated by the lack of proper tooling around migrations - no more) users ;)&lt;/p&gt;
&lt;p&gt;Please take a look at how the code looks like and I hope you find it easy to extend to your own
needs. Any suggestions and feedback are very welcome, specially now that the project is new and
we can change a lot before it gets a stable API.&lt;/p&gt;
&lt;p&gt;May I count with your help? ;)&lt;/p&gt;
</content:encoded></item><item><title>Testing HTTPS in a Linux development environment with self-signed certificates</title><link>https://rosenfeld.page/articles/programming/2017_12_01_testing_https_in_a_linux_development_environment_with_self_signed_certificates/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2017_12_01_testing_https_in_a_linux_development_environment_with_self_signed_certificates/</guid><pubDate>Fri, 01 Dec 2017 19:12:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Note: if you only care about getting the certificates, jump to the end of the article and
you&amp;#39;ll find a button to just do that. This way you don&amp;#39;t even need Linux to generate them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For a long time I&amp;#39;ve been testing my application locally using a certificate issued by Let&amp;#39;s
encrypt, which I must renew every few months for domains such as dev.mydomain.com. Recently,
I&amp;#39;ve been considering creating a new app and I don&amp;#39;t have a domain for it yet.&lt;/p&gt;
&lt;p&gt;So I decided to take some time to learn how to create self-signed certificates in such a way
that browsers such as Chrome and Firefox would accept it without any disclaimer with no extra step.&lt;/p&gt;
&lt;p&gt;It took me about 2 hours to be able achieve this task, so I decided to write it down so that it
would save me time in the future when I need to repeat this process.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ll use the myapp.example.com domain for my new app, since the example.com domain is reserved.&lt;/p&gt;
&lt;p&gt;The first step is add that domain in /etc/hosts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;127.0.0.1   localhost myapp.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recent browsers will require the subject alternate names extension, so the script will generate
that extension using a template like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;[SAN]
subjectAltName = @alternate_names

[ alternate_names ]

DNS.1 = myapp.example.com
IP.1  = 127.0.0.1
IP.2  = 192.168.0.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the second IP with your own fixed IP if you have one just in case you need to access it
from another computer in the network, like some VM, for example. Edit the script below to change
the template. You&amp;#39;ll need to add the root CA certificate we&amp;#39;ll generate soon to those other
computers in the network in order to do so, as I&amp;#39;ll explain in the last steps in this article.
Just remove IP.2 if you don&amp;#39;t care about it.&lt;/p&gt;
&lt;p&gt;Then create this script to help generating the certificates in ~/.ssl/generate-certificates:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;#!/bin/bash

FQDN=${1:-myapp.example.com}

# Create our very own Root Certificate Authority

[ -f my-root-ca.key.pem ] || \
openssl genrsa -out my-root-ca.key.pem 2048

# Self-sign our Root Certificate Authority

[ -f my-root-ca.crt.pem ] || \
openssl req -x509 -new -nodes -key my-root-ca.key.pem -days 9131 \
  -out my-root-ca.crt.pem \
  -subj &amp;quot;/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.net&amp;quot;

# Create Certificate for this domain

[ -f ${FQDN}.privkey.pem ] || \
openssl genrsa -out ${FQDN}.privkey.pem 2048

# Create the extfile including the SAN extension

cat &amp;gt; extfile &amp;lt;&amp;lt;EOF
[SAN]
subjectAltName       = @alternate_names

[ alternate_names ]

DNS.1       = ${FQDN}
IP.1        = 127.0.0.1
IP.2        = 192.168.0.10
EOF

# Create the CSR

[ -f ${FQDN}.csr.pem ] || \
openssl req -new -key ${FQDN}.privkey.pem -out ${FQDN}.csr.pem \
  -subj &amp;quot;/C=US/ST=Utah/L=Provo/O=ACME Service/CN=${FQDN}&amp;quot; \
  -reqexts SAN -extensions SAN \
  -config &amp;lt;(cat /etc/ssl/openssl.cnf extfile)

# Sign the request from Server with your Root CA

[ -f ${FQDN}.cert.pem ] || \
openssl x509 -req -in ${FQDN}.csr.pem \
  -CA my-root-ca.crt.pem \
  -CAkey my-root-ca.key.pem \
  -CAcreateserial \
  -out ${FQDN}.cert.pem \
  -days 9131 \
  -extensions SAN \
  -extfile extfile

# Update this machine to accept our own root CA as a valid one:

sudo cp my-root-ca.crt.pem /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates

cat &amp;lt;&amp;lt;EOF
Here&amp;#39;s a sample nginx config file:

server {
        listen 80;
        listen 443 ssl;

        ssl_certificate ${PWD}/${FQDN}.cert.pem;
        ssl_certificate_key ${PWD}/${FQDN}.privkey.pem;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name ${FQDN};

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }
}
EOF

grep -q ${FQDN} /etc/hosts || echo &amp;quot;Remember to add ${FQDN} to /etc/hosts&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cd ~/.ssl
chmod +x generate-certificates
./generate-certificates # will generate the certificates for myapp.example.com

# to generate for another app:
./generate-certificates otherapp.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script will output a sample nginx file demonstrating how to use the certificate and will
remind you about adding the entry to /etc/hosts if it detects the domain is not present already.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s it. Even curl should work out-of-the-box, just like browsers such as Chrome and Firefox:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -I https://myapp.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you need to install the root certificate in other computers in the network (or VMs), it&amp;#39;s
located in ~/.ssl/my-root-ca.crt.pem. If the other computers are running Linux:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# The .crt extension is important
sudo cp my-root-ca.crt.pem /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I didn&amp;#39;t research about how to install them in other OS, so please let me know in the comments if
you know and I&amp;#39;ll update the article explaining the instructions for setting up VM guests of other
operating systems.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve also created a Docker container with a simple Ruby Rack application to generate those certs.
The code is simple and &lt;a href=&quot;https://github.com/rosenfeld/cert-generator&quot;&gt;is available at Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also &lt;a href=&quot;https://hub.docker.com/r/rosenfeld/cert-generator/&quot;&gt;published to Docker Hub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can give it a try here:&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;270px&quot; src=&quot;https://cert-generator-igncqyxuro.now.sh/&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;I hope you&amp;#39;ll find it useful as much as I do ;)&lt;/p&gt;
</content:encoded></item><item><title>Upgrading PostgreSQL from 9.6 to 10 with minimal downtime using pglogical</title><link>https://rosenfeld.page/articles/infrastructure/2017_11_10_upgrading_postgresql_from_9_6_to_10_with_minimal_downtime_using_pglogical/</link><guid isPermaLink="true">https://rosenfeld.page/articles/infrastructure/2017_11_10_upgrading_postgresql_from_9_6_to_10_with_minimal_downtime_using_pglogical/</guid><pubDate>Fri, 10 Nov 2017 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Once PostgreSQL 10 was released I wanted to upgrade our 9.6 cluster to the newest version. However,
it would require a lot of coordination effort to get a maintenance window to perform the migration
the way I was used to: put the application in maintenance mode, get a new dump and restore it to
the new cluster and switch off the maintenance mode.&lt;/p&gt;
&lt;p&gt;That means the application wouldn&amp;#39;t be available for an hour or so, maybe more. After reading once
more about &lt;a href=&quot;https://www.2ndquadrant.com/en/resources/pglogical/&quot;&gt;pglogical&lt;/a&gt;, I decided to finally
give it a try, which allowed me to switch from 9.6 to 10 in just a few seconds.&lt;/p&gt;
&lt;h2&gt;How it works - a higher level view&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;pglogical&lt;/em&gt; implements logical replication, which allows replicating databases among different
versions, which is not possible with the binary replication mechanism provided by PostgreSQL
itself. Well, PG 10 added some support to logical replication, but since we want to replicate
from 9.6, we&amp;#39;d need to resort to some external extension.&lt;/p&gt;
&lt;p&gt;A required condition from &lt;em&gt;pglogical&lt;/em&gt; is that all tables being replicated must have a primary key.
It doesn&amp;#39;t need to be a single column, but a primary key must exist. Superuser access must also
be provided for both databases for the replication agents. DDL replication is not supported.
Truncate cascades are not replicated. Nothing fancy, after all. It should allow us to replicate
most databases.&lt;/p&gt;
&lt;p&gt;You should pay special attention to the primary key requirement though, specially if you&amp;#39;re
using the ActiveRecord Ruby gem to manage the database migrations in older databases as the
&lt;em&gt;schema_migrations&lt;/em&gt; table didn&amp;#39;t have a primary key in the earlier days. If that&amp;#39;s your case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;alter table schema_migrations add primary key (version);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The idea is to install a PostgreSQL package with support for the pglogical extension, then
create the new PG 10 cluster and restore the schema only in the new cluster. The current cluster
should be stopped and restarted using the pglogical-enabled installed PostgreSQL. The
clusters should be reachable to it other through TCP/IP. You&amp;#39;ll need to tell the provider
(the 9.6 database being upgraded) the IP and port for the subscriber (the new PG 10 database)
and vice-versa. The &lt;em&gt;pglogical&lt;/em&gt; extension is created in both databases, &lt;em&gt;postgresql.conf&lt;/em&gt; and
&lt;em&gt;pg_hba.conf&lt;/em&gt; are changed to enable logical replication and both databases are restarted.
Finally, some &lt;em&gt;pglogical&lt;/em&gt; statements are issued to create the provider, subscriber and
subscription, which starts the replication. Once the replication is finished, you may change
the port in the new cluster to match the old one, stop the old cluster and restart the new one.
Finally it would be a good idea to restart the applications as well, specially if you&amp;#39;re using
some custom types such as row types, as they will most likely have different OIDs and if you
have registered those row types it won&amp;#39;t work as expected until you reboot the application.
This would be the case if you&amp;#39;re using &lt;em&gt;DB.register_row_type&lt;/em&gt; using the Sequel Ruby gem, for
example.&lt;/p&gt;
&lt;p&gt;The final switch can happen in as quickly as a few seconds, which means minimal downtime.&lt;/p&gt;
&lt;h2&gt;How it works - hands on&lt;/h2&gt;
&lt;p&gt;We use Docker to run PostgreSQL in our servers (besides the apps), so this article also uses it to
demonstrate how the process works, but it should be easy to apply the instructions to other kind
of set-ups. The advantage of Docker as demonstration tool is that these procedures should be
easy to replicate as is and it also takes care of creating and running the databases as well.&lt;/p&gt;
&lt;p&gt;We assume the PostgreSQL client is installed in the host too for this article.&lt;/p&gt;
&lt;h3&gt;Prepare the images and start-up script&lt;/h3&gt;
&lt;p&gt;Create the following Dockerfiles in sub-directories pg96 and pg10 (look at the instructions
inside the Dockerfiles in order to replicate in your own environment if you&amp;#39;re not running
PostgreSQL in a Docker container):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;# pg96/Dockerfile
FROM postgres:9.6

RUN apt-get update &amp;amp;&amp;amp; apt-get install -y wget gnupg
RUN echo &amp;quot;deb [arch=amd64] http://packages.2ndquadrant.com/pglogical/apt/ jessie-2ndquadrant main&amp;quot; &amp;gt; /etc/apt/sources.list.d/2ndquadrant.list \
  &amp;amp;&amp;amp; wget --quiet -O - http://packages.2ndquadrant.com/pglogical/apt/AA7A6805.asc | apt-key add - \
  &amp;amp;&amp;amp; apt-get update \
  &amp;amp;&amp;amp; apt-get install -y postgresql-9.6-pglogical

RUN echo &amp;quot;host    replication          postgres                172.18.0.0/16   trust&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/9.6/pg_hba.conf.sample
RUN echo &amp;quot;host    replication          postgres                ::1/128         trust&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/9.6/pg_hba.conf.sample
RUN echo &amp;quot;shared_preload_libraries = &amp;#39;pglogical&amp;#39;&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
RUN echo &amp;quot;wal_level = &amp;#39;logical&amp;#39;&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
RUN echo &amp;quot;max_wal_senders = 20&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
RUN echo &amp;quot;max_replication_slots = 20&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;# pg10/Dockerfile
FROM postgres:10

RUN rm /etc/apt/trusted.gpg &amp;amp;&amp;amp; apt-get update &amp;amp;&amp;amp; apt-get install -y wget
RUN echo &amp;quot;deb [arch=amd64] http://packages.2ndquadrant.com/pglogical/apt/ stretch-2ndquadrant main&amp;quot; &amp;gt; /etc/apt/sources.list.d/2ndquadrant.list \
  &amp;amp;&amp;amp; wget --quiet -O - http://packages.2ndquadrant.com/pglogical/apt/AA7A6805.asc | apt-key add - \
  &amp;amp;&amp;amp; apt-get update \
  &amp;amp;&amp;amp; apt-get install -y postgresql-10-pglogical

RUN echo &amp;quot;host    replication          postgres                172.18.0.0/16   trust&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/10/pg_hba.conf.sample
RUN echo &amp;quot;host    replication          postgres                ::1/128         trust&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/10/pg_hba.conf.sample
RUN echo &amp;quot;shared_preload_libraries = &amp;#39;pglogical&amp;#39;&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
RUN echo &amp;quot;wal_level = &amp;#39;logical&amp;#39;&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
RUN echo &amp;quot;max_wal_senders = 20&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
RUN echo &amp;quot;max_replication_slots = 20&amp;quot; &amp;gt;&amp;gt; /usr/share/postgresql/postgresql.conf.sample
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s assume both servers will run in the same machine with IP 10.0.1.10. The 9.6 instance is
running on port 5432 and the new cluster will be running initially (before the switch) in port
5433.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cd pg96 &amp;amp;&amp;amp; docker build . -t postgresql-pglogical:9.6 &amp;amp;&amp;amp; cd -
cd pg10 &amp;amp;&amp;amp; docker build . -t postgresql-pglogical:10 &amp;amp;&amp;amp; cd -
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not a tutorial on Docker, but if you&amp;#39;re actually using Docker, it would be a good idea to
push those images to your private registry.&lt;/p&gt;
&lt;p&gt;The first step is to stop the old 9.6 cluster and start the &lt;em&gt;pglogical&lt;/em&gt; enabled cluster with the
old data (taking a backup before is always a good idea by the way). Suppose your cluster data is
located at &amp;quot;/var/lib/postgresql/9.6/main/&amp;quot; and that your config files are located at
&amp;quot;/etc/postgresql/9.6/main/&amp;quot;. If &amp;quot;/etc/postgresql/9.6&amp;quot; and &amp;quot;/var/lib/postgresql/9.6&amp;quot; do not exist,
don&amp;#39;t worry, the script will create a new cluster for you (in case you want to try with new dbs,
first, which is a good idea by the way, and map some temp directories).&lt;/p&gt;
&lt;p&gt;Create the following script at &amp;quot;/sbin/pg-scripts/start-pg&amp;quot; and make it executable. It will run
the database from the container.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;#!/bin/bash
version=$1
net=$2
setup_db(){
  pg_createcluster $version main -o listen_addresses=&amp;#39;*&amp;#39; -o wal_level=logical \
        -o max_wal_senders=10 -o max_worker_processes=10 -o max_replication_slots=10 \
        -o hot_standby=on -o max_wal_senders=10 -o shared_preload_libraries=pglogical -- -A trust
  pghba=/etc/postgresql/$version/main/pg_hba.conf
  echo -e &amp;quot;host\tall\tappuser\t$net\ttrust&amp;quot; &amp;gt;&amp;gt; $pghba
  echo -e &amp;quot;host\treplication\tappuser\t$net\ttrust&amp;quot; &amp;gt;&amp;gt; $pghba
  echo -e &amp;quot;host\tall\tpostgres\t172.17.0.0/24\ttrust&amp;quot; &amp;gt;&amp;gt; $pghba
  echo -e &amp;quot;host\treplication\tpostgres\t172.17.0.0/24\ttrust&amp;quot; &amp;gt;&amp;gt; $pghba
  pg_ctlcluster $version main start
  psql -U postgres -c &amp;#39;\du&amp;#39; postgres|grep -q appuser || createuser -U postgres -l -s appuser
  pg_ctlcluster $version main stop
}
[ -d /var/lib/postgresql/$version/main ] || setup_db
exec pg_ctlcluster --foreground $version main start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script will take care of creating a new cluster if one doesn&amp;#39;t already exist. Although not
really required for the replication to work, it also takes care of creating a new &amp;quot;appuser&amp;quot;
database superuser authenticated with &amp;quot;trust&amp;quot; for simplicity sake. It might be useful if you
decide to use this script for spawning new databases for testing purposes. Adapt the script to
suite your needs in that case, changing the user name or the authentication methods.&lt;/p&gt;
&lt;h3&gt;Run the containers&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s run the 9.6 cluster in port 5432 (feel free to run it in another port and use a temporary
directory in the mappings if you just want to give it a try):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run --rm -v /sbin/pg-scripts:/pg-scripts -v /var/lib/postgresql:/var/lib/postgresql \
    -v /etc/postgresql:/etc/postgresql -p 5432:5432 postgres-pglogical:9.6 \
    /pg-scripts/start-pg 9.6 10.0.1.0/24
# since we&amp;#39;re running in the foreground with the --rm option, run this in another terminal:
docker run --rm -v /sbin/pg-scripts:/pg-scripts -v /var/lib/postgresql:/var/lib/postgresql \
    -v /etc/postgresql:/etc/postgresql -p 5433:5432 postgres-pglogical:10 \
    /pg-scripts/start-pg 10 10.0.1.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first argument to &lt;em&gt;start-pg&lt;/em&gt; is the PG version and the second and last argument is the
net used to create &lt;em&gt;pg_hba.conf&lt;/em&gt; if it doesn&amp;#39;t exist, to allow &amp;quot;appuser&amp;quot; to connect from using the
&amp;quot;trust&amp;quot; authentication method.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re curious about how to run a Docker container as a systemd service, let me know in the
comments section below and I may complement this article once I find some time, but it&amp;#39;s not hard.
There are plenty of documents explaining that in the internet, but our own service unit file is
a bit different from what I&amp;#39;ve seen in most tutorials, as it tries to check that the port is
indeed accepting connections when starting the service and it doesn&amp;#39;t pull the image from the
registry if it is available locally already.&lt;/p&gt;
&lt;h3&gt;Edit PostgreSQL configuration&lt;/h3&gt;
&lt;p&gt;Once you make sure the old cluster is running file with the postgresql-pglogical container, it&amp;#39;s
time to update your &lt;em&gt;postgresql.conf&lt;/em&gt; file and restart the container. Use the following
configuration as a start-point for both 9.6 and 10 clusters:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;wal_level = logical
max_worker_processes = 10
max_replication_slots = 10
max_wal_senders = 10
shared_preload_libraries = &amp;#39;pglogical&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For &lt;em&gt;pg_hba.conf&lt;/em&gt;, include the following lines (change the network settings if you&amp;#39;re not using
Docker, or if you&amp;#39;re running the containers in another net than the default one):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;host    all     postgres        172.17.0.0/24   trust
host    replication     postgres        172.17.0.0/24   trust
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart the servers and we should be ready for starting the replication.&lt;/p&gt;
&lt;h2&gt;Replicating the database&lt;/h2&gt;
&lt;h3&gt;Set up the provider&lt;/h3&gt;
&lt;p&gt;In the PG 9.6 database:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# take a dump from the schema that we&amp;#39;ll use to restore in PG 10
pg_dump -Fc -s -h 10.0.1.10 -p 5432 -U appuser mydb &amp;gt; mydb-schema.dump
psql -h 10.0.1.10 -p 5432 -c &amp;#39;create extension pglogical;&amp;#39; -U appuser mydb
psql -h 10.0.1.10 -p 5432 -c &amp;quot;select pglogical.create_node(node_name := &amp;#39;provider&amp;#39;, dsn := &amp;#39;host=10.0.1.10 port=5432 dbname=mydb&amp;#39;);&amp;quot; -U appuser mydb
psql -h 10.0.1.10 -p 5432 -c &amp;quot;select pglogical.replication_set_add_all_tables(&amp;#39;default&amp;#39;, ARRAY[&amp;#39;public&amp;#39;]);&amp;quot; -U appuser mydb

# I couldn&amp;#39;t get sequences replication to work, so I&amp;#39;ll suggest another method just before switching the database
# psql -h 10.0.1.10 -p 5432 -c &amp;quot;select pglogical.replication_set_add_all_sequences(&amp;#39;default&amp;#39;, ARRAY[&amp;#39;public&amp;#39;]);&amp;quot; -U appuser mydb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This mark all tables and sequences from the public schema to be replicated.&lt;/p&gt;
&lt;h3&gt;Set up the subscriber and subscription&lt;/h3&gt;
&lt;p&gt;In the PG 10 database:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# create and restore the schema of the database
createdb -U appuser -h 10.0.1.10 -p 5433 mydb
pg_restore -s -h 10.0.1.10 -p 5433 -U appuser -d mydb mydb-schema.dump
# install the pglogical extension and setup the subscriber and subscription
psql -h 10.0.1.10 -p 5433 -c &amp;#39;create extension pglogical;&amp;#39; -U appuser mydb
psql -h 10.0.1.10 -p 5433 -c &amp;quot;select pglogical.create_node(node_name := &amp;#39;subscriber&amp;#39;, dsn := &amp;#39;host=10.0.1.10 port=5433 dbname=mydb&amp;#39;);&amp;quot; -U appuser mydb
psql -h 10.0.1.10 -p 5433 -c &amp;quot;select pglogical.create_subscription(subscription_name := &amp;#39;subscription&amp;#39;, provider_dsn := &amp;#39;host=10.0.1.10 port=5432 dbname=mydb&amp;#39;);&amp;quot; -U appuser mydb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From now on you can follow the status of the replication with&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select pglogical.show_subscription_status(&amp;#39;subscription&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the initialization is over and the databases are synced and replicating (this may take quite
a while depending on your database size) you may start the switch.&lt;/p&gt;
&lt;h3&gt;Replicating the sequence values&lt;/h3&gt;
&lt;p&gt;At this point the replication database is almost all set. I couldn&amp;#39;t figure out how to replicate
the sequence values, so, if you&amp;#39;re using serial integer primary key columns relying on sequences,
then you&amp;#39;ll also want to set proper values to the sequences otherwise you won&amp;#39;t be able to
insert new records while relying on the serial sequence next value. Here&amp;#39;s how you can do that.
Just to be sure, it&amp;#39;s inserting a 5000 gap so that you have enough time to stop the old server
after gererating the set-value statements in case your database is very write intensive. You
should probably review that gap value depending on how quickly your database might grow up between
running those scripts and stopping the server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;psql -h 10.0.1.10 -p 5432 -U appuser -c &amp;quot;select string_agg(&amp;#39;select &amp;#39;&amp;#39;select setval(&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39; || relname || &amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;, &amp;#39;&amp;#39; || last_value + 5000 || &amp;#39;&amp;#39;)&amp;#39;&amp;#39; from &amp;#39; || relname, &amp;#39; union &amp;#39; order by relname) from pg_class where relkind =&amp;#39;S&amp;#39;;&amp;quot; -t -q -o set-sequences-values-generator.sql mydb
psql -h 10.0.1.10 -p 5432 -U appuser -t -q -f set-sequences-values-generator.sql -o set-sequences-values.sql mydb
# set the new sequence values in the new database (port 5433 in this example):
psql -h 10.0.1.10 -p 5433 -U appuser -f set-sequences-values.sql mydb
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Final switch steps&lt;/h3&gt;
&lt;p&gt;Then, basically, you should change the port for the PG10 cluster and set it to 5432 (or whatever
was the port the old cluster was using).  Then stop the 9.6 cluster (Ctrl+C in the example above)
and restart the new cluster. Finally, it&amp;#39;s a good idea to also restart the apps using the
database, just in case they are relying on some custom types whose conversion rules would depend
on the row type OID.&lt;/p&gt;
&lt;p&gt;This assumes your apps are able to gracefully handle disconnections for the connections in the
pool by using some connection validation before issuing any SQL statements. Otherwise, it&amp;#39;s
probably a good idea to restart the apps whenever you restart the database after tweaking
&amp;quot;postgresql.conf&amp;quot; and &amp;quot;pg_hba.conf&amp;quot;.&lt;/p&gt;
&lt;h2&gt;Clean-up&lt;/h2&gt;
&lt;p&gt;Once everything is running fine with the new database, you might want to clean things up. If that&amp;#39;s
the case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select pglogical.drop_subscription(&amp;#39;subscription&amp;#39;);
select pglogical.drop_node(&amp;#39;subscriber&amp;#39;);
drop extension pglogical;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hope that helps you getting your database upgraded with minimal downtime.&lt;/p&gt;
</content:encoded></item><item><title>Explicit request params binding in Ruby web apps (or &quot;convenience can be inconvenient&quot;)</title><link>https://rosenfeld.page/articles/ruby-rails/2017_10_13_explicit_request_params_binding_in_ruby_web_apps/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2017_10_13_explicit_request_params_binding_in_ruby_web_apps/</guid><pubDate>Fri, 13 Oct 2017 19:50:00 GMT</pubDate><content:encoded>&lt;p&gt;The Ruby ecosystem is famous for providing convenient ways of doing things. Very often
security concerns are traded for more convenience. That makes me feel out of place because
I&amp;#39;m always struggling to change the default route since I&amp;#39;m not interested in trading
security with convenience when I have to make a choice.&lt;/p&gt;
&lt;p&gt;Since it&amp;#39;s Friday 13, let&amp;#39;s talk a bit about my fears ;)&lt;/p&gt;
&lt;p&gt;I remember that several of the security issues that were disclosed in the past few years
in the Ruby community only existed in the first place because of this idea that we should
try to deliver features the most convenient way. Like allowing YAML to dump/load Ruby objects,
for example, when people were used to use it to serialize/deserialize. Thankfully it seems
JSON is more popular these days even if more limited - you can&amp;#39;t serialize times or dates,
for example, as allowed in YAML.&lt;/p&gt;
&lt;p&gt;Here are some episodes I can remember of regarding how convenience was the reason behind many
vulnerabilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.codeclimate.com/blog/2013/01/10/rails-remote-code-execution-vulnerability-explained/&quot;&gt;Remote code execution due to convenience methods added to XML and YAML, 2013&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;DoS caused by Rack conveniently converting params to hashes automatically: &lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!msg/rubyonrails-security/jgJ4cjjS8FE/BGbHRxnDRTIJ&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/8CVoclw-Xkk&quot;&gt;2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/rgO20zYW33s&quot;&gt;Params injection caused by Rack conveniently converting params to arrays automatically&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Remote code execution due to &lt;code&gt;render&lt;/code&gt; conveniently accepting multiple arguments formats: &lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/ly-IH-fxr_Q&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/ly-IH-fxr_Q&quot;&gt;2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/7VlB_pck3hU&quot;&gt;XSS vulnerability due to adding convenient JSON encoding features&lt;/a&gt; - 
For several years I only rely on the &amp;#39;json&amp;#39; stdlib to parse and encode JSON using
::JSON.parse/unparse and don&amp;#39;t use any sort of &lt;em&gt;.to_json&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/KtmwSbEpzrU&quot;&gt;More vulnerabilities in name of convenience&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;many more examples, but you got my point hopefully.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I remember that for a long while I was used to always explicitly convert params to the expected
format, like &lt;em&gt;params[:name].to_s&lt;/em&gt; and that alone was enough to protect my application from many
of the disclosed vulnerabilities. But my application was still vulnerable to the first mentioned
in the list above and the worst part is that we never ever used XML or YAML in our controllers
but we were affected by that bug in the name of convenience (for others, not us).&lt;/p&gt;
&lt;h2&gt;Why is this a major issue with Ruby web applications?&lt;/h2&gt;
&lt;p&gt;Any other web framework providing seamless params binding depending on how the params keys are
formatted are vulnerable for the same reasons but most (all?) people doing web development with
Ruby these days will rely on &lt;em&gt;Rack::Request&lt;/em&gt; somehow. And it will automatically convert your
params to array if they are formatted like &lt;em&gt;?a[]=1&amp;amp;a[]=2&lt;/em&gt; or hashes if they are formatted like
&lt;em&gt;?a[x]=1&amp;amp;a[y]=2&lt;/em&gt;. This is built-in and you can&amp;#39;t change this behavior for your specific
application. I mean, you could replace &lt;em&gt;Rack::Utils.default_query_parser&lt;/em&gt; and implement
&lt;em&gt;parse_nested_query&lt;/em&gt; as &lt;em&gt;parse_query&lt;/em&gt; for your own custom parser but then that would apply to
other Rack apps mounted in your app (think of Sidekiq web, for example) and you don&amp;#39;t know
whether or not they&amp;#39;re relying on such conveniences.&lt;/p&gt;
&lt;h2&gt;How to improve things&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been bothered by the inconvenience of having to add &lt;em&gt;.to_s&lt;/em&gt; to all string params (in name
of providing more convenience, which is ironic anyway) for many reasons, and wanted a
more convenient way of accessing params safely for years. As you can see, what is
convenient to some can be inconvenient to others. But that would require a manual inspection in
all controllers to review all cases where a param is fetched from the request. I wasn&amp;#39;t that
much bothered after all, so I thought it wouldn&amp;#39;t worth the effort for such a big app.&lt;/p&gt;
&lt;p&gt;Recently I noticed Rack recently deprecated &lt;em&gt;Rack::Request#[]&lt;/em&gt; and I used it a lot as not only it
was more convenient calling &lt;em&gt;request[&amp;#39;name&amp;#39;]&lt;/em&gt; instead of &lt;em&gt;request.params[&amp;#39;name&amp;#39;]&lt;/em&gt; but most
examples in Roda&amp;#39;s README used that convenient &lt;em&gt;#[]&lt;/em&gt; method (the examples were updated after
it was deprecated). Since eventually I&amp;#39;d have to fix all usage of such method, and once they were
used all over the places in our Roda apps (think of controllers - we use the &lt;em&gt;multi_run&lt;/em&gt; plugin),
I decided to finally take a step further and fix the old problem as well.&lt;/p&gt;
&lt;h3&gt;Fetching params through an specialized safer class&lt;/h3&gt;
&lt;p&gt;Since I realized that it wouldn&amp;#39;t be possible to make Rack parse queries in a more simpler way,
I decided to build a solution that would wrap around Rack parsed params. For a Roda app, like ours,
writing a Roda plugin for that makes perfect sense, so this is what I did:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# apps/plugins/safe_request_params.rb
require &amp;#39;rack/request&amp;#39;
require &amp;#39;json&amp;#39;

module AppPlugins
  module SafeRequestParams
    class Params
      attr_reader :files, :arrays, :hashes

      def initialize(env: nil, request: nil)
        request ||= Rack::Request.new(env)
        @params = {}
        @files = {}
        @arrays = {}
        @hashes = {}
        request.params.each do |name, value|
          case value
          when String then @params[name] = value
          when Array then @arrays[name] = value
          when Hash
            if value.key? :tempfile
              @files[name] = UploadedFile.new value
            else
              @hashes[name] = value
            end
          end # ignore if none of the above
        end
      end

      # a hash representing all string values and their names
      # pass the keys you&amp;#39;re interested at optionally as an array
      def to_h(keys = nil)
        return @params unless keys
        keys.each_with_object({}) do |k, r|
          k = to_s k
          next unless key? k
          r[k] = self[k]
        end
      end

      # has a string value for that key name?
      def key?(name)
        @params.key?(to_s name)
      end

      def file?(name)
        @files.key?(to_s name)
      end

      # WARNING: be extra careful to verify the array is in the expected format
      def array(name)
        @arrays[to_s name]
      end

      # has an array value with that key name?
      def array?(name)
        @arrays.key?(to_s name)
      end

      # WARNING: be extra careful to verify the hash is in the expected format
      def hash_value(name)
        @hashes[to_s name]
      end

      # has a hash value with that key name?
      def hash?(name)
        @hashes.key?(to_s name)
      end

      # returns either a string or nil
      def [](name, nil_if_empty: true, strip: true)
        value = @params[to_s name]
        value = value&amp;amp;.strip if strip
        return value unless nil_if_empty
        value&amp;amp;.empty? ? nil : value
      end

      def file(name)
        @files[to_s name]
      end

      # raises if it can&amp;#39;t convert with Integer(value, 10)
      def int(name, nil_if_empty: true, strip: true)
        return nil unless value = self[name, nil_if_empty: nil_if_empty, strip: strip]
        to_int value
      end

      # converts a comma separated list of numbers to an array of Integer
      # raises if it can&amp;#39;t convert with Integer(value, 10)
      def intlist(name, nil_if_empty: true, strip: nil)
        return nil unless value = self[name, nil_if_empty: nil_if_empty, strip: strip]
        value.split(&amp;#39;,&amp;#39;).map{|v| to_int v }
      end

      # converts an array of strings to an array of Integer. The query string is formatted like:
      # ids[]=1&amp;amp;ids[]=2&amp;amp;...
      def intarray(name)
        return nil unless value = array(name)
        value.map{|v| to_int v }
      end

      # WARNING: be extra careful to verify the parsed JSON is in the expected format
      # raises if JSON is invalid
      def json(name, nil_if_empty: true)
        return nil unless value = self[name, nil_if_empty: nil_if_empty]
        JSON.parse value
      end

      private

      def to_s(name)
        Symbol === name ? name.to_s : name
      end

      def to_int(value)
        Integer(value, 10)
      end

      class UploadedFile
        ATTRS = [ :tempfile, :filename, :name, :type, :head ]
        attr_reader *ATTRS
        def initialize(file)
          @file = file
          @tempfile, @filename, @name, @type, @head = file.values_at *ATTRS
        end

        def to_h
          @file
        end
      end
    end

    module InstanceMethods
      def params
        env[&amp;#39;app.params&amp;#39;] ||= Params.new(request: request)
      end
    end
  end
end

Roda::RodaPlugins.register_plugin :app_safe_request_params, AppPlugins::SafeRequestParams
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s how it&amp;#39;s used in apps (controllers):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require_relative &amp;#39;base&amp;#39;
module Apps
  class MyApp &amp;lt; Base
    def process(r) # r is an alias to self.request
      r.post(&amp;#39;save&amp;#39;){ save }
    end

    private

    def save
      assert params[:name] === params[&amp;#39;name&amp;#39;]
      # Suppose a file is passed as the &amp;quot;file_param&amp;quot;
      assert params[&amp;#39;file_param&amp;#39;].nil?
      refute params.file(&amp;#39;file_param&amp;#39;).tempfile.nil?
      p params.files.map(&amp;amp;:filename)
      p params.json(:json_param)[&amp;#39;name&amp;#39;]
      p [ params.int(:age), params.intlist(:ids) ]
      assert params[&amp;#39;age&amp;#39;] == &amp;#39;36&amp;#39;
      assert params.int(:age) == 36

      # we don&amp;#39;t currently use this in our application, but in case we wanted to take advantage
      # of the convenient query parsing that will automatically convert params to hashes or arrays:
      children = params.array &amp;#39;children&amp;#39;
      assert params[&amp;#39;children&amp;#39;].nil?
      user = params.hash_value :user
      name = user[&amp;#39;name&amp;#39;].to_s

      # some convenient behavior we appreciate in our application:
      assert request.params[&amp;#39;child_name&amp;#39;] == &amp;#39;   &amp;#39;
      assert params[&amp;#39;child_name&amp;#39;].nil? # we call strip on the values and convert to nil if empty
    end
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An idea for those wanting to expand the safeness of the &lt;code&gt;Params&lt;/code&gt; class above to the unsafe
methods (&lt;em&gt;json&lt;/em&gt;, &lt;em&gt;array&lt;/em&gt;, &lt;em&gt;hash_value&lt;/em&gt;) one could implement it in such a way that any hashes
would be wrapped in a &lt;em&gt;Params&lt;/em&gt; instance. However they should probably consider more specialized
solutions in those cases, such as &lt;a href=&quot;http://dry-rb.org/gems/dry-validation/&quot;&gt;dry-validation&lt;/a&gt; or
&lt;a href=&quot;https://github.com/nesaulov/surrealist&quot;&gt;surrealist&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Final notes&lt;/h2&gt;
&lt;p&gt;In web frameworks developed in static languages this isn&amp;#39;t often a common reason for vulnerability
because it&amp;#39;s harder to implement solutions like the one adopted by Rack as one would have to
use some generic type such as &lt;em&gt;Object&lt;/em&gt; for mappings params keys to their values, which is usually
avoided in typed languages. Also, method signatures are often more explicit which prevents an
specially crafted param to be interpreted as being of a different type than expected by methods.
This is even more true in languages that don&amp;#39;t support method overloading, such as Java.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s one of the reasons I like the idea of introducing optional typing to Ruby, as
&lt;a href=&quot;https://bugs.ruby-lang.org/issues/6711&quot;&gt;I once proposed&lt;/a&gt;. I do like the flexibility of Ruby and
that&amp;#39;s one of the reasons why I often preferred script languages over static ones for general
purpose programming (I used to do Perl programming in my initial days when developing to the web).&lt;/p&gt;
&lt;p&gt;But if Ruby was flexible enough to also allow me to specify optional typing, like Groovy does, it
would be even better in my opinion. Until there, even though I&amp;#39;m not an security expert by any
means, I feel like the recent changes on how our app fetch params from the request should
significantly reduce the possibility of introducing bugs caused by params injection in general.&lt;/p&gt;
&lt;p&gt;After all, security is already a quite complex topic to me and I don&amp;#39;t even want to have to think
about what would be the impact of doing something like
&lt;em&gt;MyModel.where(username: params[&amp;#39;username&amp;#39;])&lt;/em&gt; and have to think what could possibly go wrong if
someone would inject some special array or hash in the &lt;em&gt;username&lt;/em&gt; param. Security is already
hard to get it right. No need to make it even harder by providing automatic params binding
through the same method out of the box in the name of convenience.&lt;/p&gt;
</content:encoded></item><item><title>The day I reached the 1600 columns limit in PostgreSQL</title><link>https://rosenfeld.page/articles/programming/2017_09_26_the_day_i_reached_the_1600_columns_limit_in_postgresql/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2017_09_26_the_day_i_reached_the_1600_columns_limit_in_postgresql/</guid><pubDate>Tue, 26 Sep 2017 11:15:00 GMT</pubDate><content:encoded>&lt;p&gt;WARNING: skip the TLDR section if you like some drama.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TLDR: PostgreSQL doesn&amp;#39;t reclaim space when dropping a column. If you use some script that will
add temporary columns and run it many times at some point it will reach the 1600 max columns per
table limit.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It was a Friday afternoon (it&amp;#39;s always on Friday, right?) and we were close to start a long
awaited migration process and after several tests everything seemed to be working just fine, until
someone told me they were no longer able to continue testing as the servers wouldn&amp;#39;t allow them
to port deals anymore. After a quick inspection in the logs I noticed the message saying we had
reached the 1600 columns per table limit in PostgreSQL.&lt;/p&gt;
&lt;p&gt;If you never got into this situation (and if you haven&amp;#39;t read the TLDR) you might be wondering:
&amp;quot;how the hell would someone get 1600 columns in a single table?!&amp;quot;. Right? I was just as impressed,
although I already suspected what could be happening, since I knew the script would create
temporary columns to store the previous reference ids when inserting new records, even though they
were dropped by the end of the transaction.&lt;/p&gt;
&lt;p&gt;If that didn&amp;#39;t happen to you, you might think I was the first to face this issue but you&amp;#39;d be
wrong. A quick search in the web for the 1600 columns limit and you&amp;#39;ll find many more cases of
people unexpectedly reaching this limit without actually having that many columns in the table.
I wasn&amp;#39;t the first one and won&amp;#39;t be the last one to face this issue but, luckily for you who are
reading this article, you won&amp;#39;t be the next person to reach that limit ;)&lt;/p&gt;
&lt;h2&gt;Why using a temporary column?&lt;/h2&gt;
&lt;p&gt;Yes, now I agree it&amp;#39;s not a good idea after all, but let me try to explain why I did it in the
first place.&lt;/p&gt;
&lt;p&gt;In case you&amp;#39;re not aware, you can only use columns from the table being inserted in the &amp;quot;returning&amp;quot;
clause of some &amp;quot;insert-into-select-returning&amp;quot; statement. But I wanted to keep a mapping between
the newly inserted ids and the previous ones, from the &amp;quot;select&amp;quot; clause of the insert-into
statement. So my first idea was to simply add a temporary &amp;quot;previous_id&amp;quot; column to the table and
use it to store the old id so that I could map them.&lt;/p&gt;
&lt;p&gt;Let me give some concrete example, with tables and queries so that it gets clearer for those of
you who might be confused by the above explanation. We have documents, that can have many
references associated to it and each reference can have multiple citations. The actual model is
as much complicated as irrelevant to the problem, so let me simplify it to make my point.&lt;/p&gt;
&lt;p&gt;Suppose we want to duplicate a document and its references and citations. We could have the
following tables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;doc_refs(id, doc_id, category_id)&lt;/li&gt;
&lt;li&gt;citations(id, ref_id, citation)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my first implementation the strategy was to add a temporary previous_id to doc_refs and then
the script would do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;insert into doc_refs(previous_id, doc_id, category_id) select id, doc_id, 30 from
  doc_refs where category_id = 20;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way it would be possible to know the mapping between the copied and pasted references so
that the script could duplicate the citations using that mapping.&lt;/p&gt;
&lt;p&gt;This script would have to run thousands of times to port all deals so, since I learned about
the columns limit and how dropping a column wouldn&amp;#39;t really reclaim space in PostgreSQL, I&amp;#39;d
need another strategy to get the mapping without resorting to some temporary column. I&amp;#39;d also
have to figure out how to reclaim that space at some point in case I&amp;#39;d need to add some additional
column for good at some point in the future, but I&amp;#39;ll discuss that part in another section below.&lt;/p&gt;
&lt;h2&gt;A better solution to the mapping problem&lt;/h2&gt;
&lt;p&gt;In case you reached those limits for the same reason as me, I&amp;#39;ll tell you how I modified the
script to use a temporary mapping table instead of a temporary column. Our tables use a serial
(integer with a generator) column. The process is just a little bit more complicated then using
the temporary column:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;create temp table refs_mapping as
  select id, nextval(&amp;#39;doc_refs_id_seq&amp;#39;) from doc_refs where category_id = 20;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that table it&amp;#39;s just a matter of inserting the records using this table to get the mapping
between the ids. Not that hard after all, and the solution is free from the columns limit issue :)&lt;/p&gt;
&lt;h2&gt;How to reclaim back the space from dropped columns?&lt;/h2&gt;
&lt;p&gt;Once the script to port deals was fixed and running I decided to take some action to reclaim the
space used by the dropped columns so that I could create new columns later in that table if I had
to.&lt;/p&gt;
&lt;p&gt;After searching the web some would tell that a full vacuum freeze would take care of rewriting the
table, which would then reclaim the space. It didn&amp;#39;t work in my tests. It seems the easiest
would be to create a dump and restore it in a new database but in our case that would mean some
downtime which I wanted to avoid. Maybe it would be possible to use this strategy with some
master-slave replication setup with no downtime, but I decided to try another strategy, which was
simpler in our case.&lt;/p&gt;
&lt;p&gt;Our clients only need read access to those tables, while the input is done by an internal team,
which is much easier for us to manage downtime if needed.&lt;/p&gt;
&lt;p&gt;So I decided to lock the table for write access while the script would recreate the table and then
I&amp;#39;d replace the old one with the new one. It took only a handful seconds to complete the operation
(the table had about 3 million records). The script looked something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;begin;
lock doc_refs in exclusive mode;
lock citations in exclusive mode;
create table new_refs (
  id integer not null primary key default nextval(&amp;#39;doc_refs_id_seq&amp;#39;),
  doc_id integer not null references documents(id),
  category_id integer not null references categories(id) on delete cascade
);
create index on new_refs(doc_id, category_id);
create index on new_refs(category_id);

insert into new_refs select * from doc_refs;

alter table citations drop constraint fk_citations_reference;
alter table doc_refs rename to old_refs;
alter table new_refs rename to doc_refs;
alter table citations add constraint fk_citations_reference
  foreign key (ref_id) references doc_refs(id) on delete cascade;
alter sequence doc_refs_id_seq owned by doc_refs.id;
commit;

-- clean-up after that:

drop table references_old;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fortunately that table was only referenced by one table, so it wasn&amp;#39;t that complicate as if that
had happened to some other tables in our database. With a simple script like that we were able
to rewrite the table with no downtime and the write access was locked for about 20 or 30 seconds
only, while the read access wasn&amp;#39;t affected at all. I hope that could be an useful trick in case
you found this article because you got yourself in a similar situation :)&lt;/p&gt;
&lt;p&gt;If you have other suggestions on how to handle the mentioned issues I&amp;#39;d love to hear from you.
I&amp;#39;m always curious about possible solutions, after all, who knows when it will be the next time
I&amp;#39;d have to think out of the box? ;) Please let me know in the comments below. Thanks :)&lt;/p&gt;
</content:encoded></item><item><title>Adopting React.js seems risky for long-term projects</title><link>https://rosenfeld.page/articles/2017_06_16_adopting_react_js_seems_risky_for_long_term_projects/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2017_06_16_adopting_react_js_seems_risky_for_long_term_projects/</guid><pubDate>Fri, 16 Jun 2017 18:10:00 GMT</pubDate><content:encoded>&lt;h2&gt;Important Update&lt;/h2&gt;
&lt;p&gt;Feel free to completely skip this article as it&amp;#39;s no longer relevant. I was confused by this part
of the React documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is important to remember that the reconciliation algorithm is an implementation detail.
React could rerender the whole app on every action; the end result would be the same.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It turns out &amp;quot;rerender&amp;quot;, as explained in the ticket I created on the React project, means calling
&lt;code&gt;render&lt;/code&gt; in all components, it doesn&amp;#39;t mean it could unmount and remount all components. If it
remounted everything as I interpreted initially, it wouldn&amp;#39;t be possible to integrate to any
third-party library, which was my main concern.&lt;/p&gt;
&lt;p&gt;That gives me enough confidence to adopt React or some of its alternative lightweight
implementations. I&amp;#39;m keeping the old content just in case you&amp;#39;re curious about it...&lt;/p&gt;
&lt;h2&gt;Old content&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been working with long-term Single Page Applications (SPA) since 2009. When you know an
application has to be maintained for many years you have to approach technology adoption very
carefully. React.js introduced a very interesting approach based on virtual DOM and reconciliation
algorithms, which seems to work great, but should it be considered safe to adopt React.js these
days?&lt;/p&gt;
&lt;p&gt;At a quick glance, the answer seems to be an obvious yes, right? React.js is used by Facebook,
one of the largest company in the world, and maintained by its team with open-source contributions.
It was largely adopted by many companies and there are some newsletters dedicated to React.js
related technologies. There are even quite some compatible implementations such as Preact.js,
Inferno.js, react-lite as well as other similar solutions such as Dio.js, MithrilJS and Maquette.
All of them taking advantage of the virtual DOM concept. That means that even if React took a
different route, or if Facebook moves to something else and stopped its maintenance, it should be
easy to move to some of its alternatives provided we use some basic set of features that should
be enough for most applications.&lt;/p&gt;
&lt;p&gt;I was really excited by the VDOM moment and all those related technologies and I understand how
they would help me to improve our current code base by not having to worry about manually managing
the DOM, which gets more bug prone as you have to update an existing DOM. We adopted Knockout.js
some years ago for parts of the application and it gave me about the same sense of making the
code easier to maintain. However embedding HTML in JavaScript components with JSX feels much
simpler to me than creating Knockout.js components (or Angular components, as they have a higher
hype these days). Also, we are very concerned about the initial load time and it seems like VDOM
based solutions can perform the initial rendering much quicker than MVVM alternatives such as
Knockout.js and Angular.js.&lt;/p&gt;
&lt;p&gt;My excitement quickly turned into fear after further reading the React official documentation,
which is great, by the way.&lt;/p&gt;
&lt;h2&gt;Third-party components support&lt;/h2&gt;
&lt;p&gt;When you have to maintain a long-term large code base, one of your main concerns will be
interoperability with third-party components. You can certainly find many articles and videos
showing how easy it is for React to use third-party components. Almost all of them will mention
returning &lt;code&gt;false&lt;/code&gt; from the &lt;code&gt;shouldComponentUpdate&lt;/code&gt; hook, or they will suggest an empty container.&lt;/p&gt;
&lt;p&gt;It turns out it currently works pretty well, but is this really supported by React? I found
React&amp;#39;s official documentation to be quite confusing regarding third-party components as it&amp;#39;s not
consistent. Here&amp;#39;s why I&amp;#39;m concerned the current approach to integrate with stateful third-party
components may no longer apply with future versions of React.js and I couldn&amp;#39;t find any official
recommendation that would be more future proof.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/facebook/react/issues/9926&quot;&gt;I&amp;#39;ve submitted an issue&lt;/a&gt;
a few days ago with my concerns, but got no response so far. Let me reproduce the issue content
here.&lt;/p&gt;
&lt;p&gt;So, here&amp;#39;s what the documentation says:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://facebook.github.io/react/docs/integrating-with-other-libraries.html&quot;&gt;https://facebook.github.io/react/docs/integrating-with-other-libraries.html&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To prevent React from touching the DOM after mounting, we will return an empty &lt;code&gt;&amp;lt;div/&amp;gt;&lt;/code&gt; from
the render() method. The element has no properties or children, so React has no reason to
update it, leaving the jQuery plugin free to manage that part of the DOM&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, it suggests using the mount/unmount hooks in order to initialize and destroy the third-party
components, however this is not enough to guarantee that the integration will succeed. I&amp;#39;ll get
more into that later.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://facebook.github.io/react/docs/reconciliation.html&quot;&gt;https://facebook.github.io/react/docs/reconciliation.html&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is important to remember that the reconciliation algorithm is an implementation detail. React
could rerender the whole app on every action; the end result would be the same.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate&quot;&gt;https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Currently, if shouldComponentUpdate() returns false, then componentWillUpdate(), render(), and
componentDidUpdate() will not be invoked. Note that in the future React may treat
shouldComponentUpdate() as a hint rather than a strict directive, and returning false may still
result in a re-rendering of the component.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Can you see the problem with that? If I can&amp;#39;t really rely on the reconciliation algorithm to not
touch the elements React is not supposed to manage, then I have no guarantees that it would be
possible to integrate React with stateful third-party components in the future.&lt;/p&gt;
&lt;p&gt;Suppose I want to integrate with a very lightweight multi-options autocomplete component that
only provides 3 public APIs, a constructor, a desctructor and some onChange hook. It&amp;#39;s an
stateful component but we don&amp;#39;t have direct access to its state so that we can restore it after
destroying and recreating it. It opens a menu with several items containing a checkbox and the
item label. As you click on the items, checking its checkbox, onChange would be triggered, which
we could use to change the state of some ancestor component managed by React.&lt;/p&gt;
&lt;p&gt;While responding to the state change event, if React simply decides to re-render the ancestor
component, without respecting shouldComponentUpdate, or if the reconciliation algorithm is not
smart enough to only perform the required changes, it means it would probably call
componentWillUnmount in the autocomplete component wrapper, which would only be able to destroy
that component. Then, after componentDidMount we would only be able to initialize the component
again, but we would have lost all of its state, like the scroll position and currently selected
item and so on. In other words, that means React wouldn&amp;#39;t be able to play nice with stateful
third-party components. In order to have such a guarantee, we need to have more guarantees from
React itself.&lt;/p&gt;
&lt;p&gt;The reconciliation algorithm shouldn&amp;#39;t be just an implementation detail without any guarantees.
shouldComponentUpdate shouldn&amp;#39;t be considered just a hint. Otherwise, how are we supposed to wrap
third-library components in a reliable way?&lt;/p&gt;
&lt;p&gt;Even though I&amp;#39;m pretty excited about VDOM based view components I&amp;#39;m not willing to give up on
existing third-party JavaScript components that require direct access to the DOM. React expects
all of your components to act like pure functions in the sense they should be able to restore
its current state by re-rendering it at any given time, even if they completely removed the mount
node&amp;#39;s contents. That basically means most UI JS components would simply break when wrapped by
a React component since they don&amp;#39;t provide such a complete API that would allow us to completely
restore its current state.&lt;/p&gt;
&lt;p&gt;At this point I&amp;#39;m not really sure I&amp;#39;m ready to give up on third-party components in order to
adopt React. But it gets worse. What if I decide I want to move to another software stack some
years from now. It&amp;#39;s important that I can draw the boundaries so that I can move one small
component at a time to the new stack. But if React is not happy with setting such strict boundaries
then in that case I&amp;#39;d have to move all at once, which doesn&amp;#39;t really work for huge code bases.&lt;/p&gt;
&lt;p&gt;If you know of any VDOM based library that provides hard boundaries and a precise diff algorithm,
please let me know in the comments below. I&amp;#39;m very interested in using VDOM, but interoperability
is so much important for me to give up from it. It allows one to incrementally change its
software stack, by mixing different stacks, replacing one component at a time for a while,
without having to rewrite the whole application which is not really feasible in most cases.&lt;/p&gt;
</content:encoded></item><item><title>Ruby on Rails: the Bad and Good parts</title><link>https://rosenfeld.page/articles/ruby-rails/2017_05_03_ruby_on_rails_the_bad_and_good_parts/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2017_05_03_ruby_on_rails_the_bad_and_good_parts/</guid><pubDate>Wed, 03 May 2017 17:40:00 GMT</pubDate><content:encoded>&lt;p&gt;In &lt;a href=&quot;/en/articles/ruby-rails/2017-05-01-feeling-alone-in-the-ruby-community-and-replacing-rails-with-roda&quot;&gt;my previous article&lt;/a&gt;,
I had a hard time trying to explain why I wanted to replace Rails with something else in the
first place. This article is my attempt to write more specifically about what I dislike in
Rails for the purpose of the single page application we maintain.&lt;/p&gt;
&lt;p&gt;In summary, in the previous article I explained that I preferred to work with more focused and
independent libraries, while Rails prefers to adopt a somewhat integrated and highly coupled
solution, which is a fine approach too. There are trade-offs involved with either approach
and I won&amp;#39;t get into the details for this article. As I said in my previous article this is
mostly about developer&amp;#39;s personal taste and mindset, so by no means I ever wanted to bash
on Rails. Quite the opposite. Rails served me pretty well for a long time and I could live
with it for many more years, so getting it out of our stack wasn&amp;#39;t an urgent matter by any
means.&lt;/p&gt;
&lt;p&gt;For the purpose of this article, I won&amp;#39;t discuss the Good and Bad of Ruby, since it was
mainly written to explain why choosing another Ruby framework instead of Rails.&lt;/p&gt;
&lt;p&gt;In case you didn&amp;#39;t read the previous article, the kind of application I work with is a single
page application, so keep this in mind when trying to understand my motivations for replacing
Rails.&lt;/p&gt;
&lt;h2&gt;Unused Rails features&lt;/h2&gt;
&lt;p&gt;So, here are some features provided by Rails which I didn&amp;#39;t use when I took the decision to
remove Rails from our stack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ActiveRecord (used Sequel instead);&lt;/li&gt;
&lt;li&gt;Turbolinks (it doesn&amp;#39;t make much sense for the kind of SPA we build);&lt;/li&gt;
&lt;li&gt;YAML configuration files (we use regular Ruby files for configuration);&lt;/li&gt;
&lt;li&gt;minitest or test/unit (used RSpec instead);&lt;/li&gt;
&lt;li&gt;fixtures (used factories instead);&lt;/li&gt;
&lt;li&gt;Devise (we have a very particular authentication strategy and authentication frameworks
wouldn&amp;#39;t add much to the table);&lt;/li&gt;
&lt;li&gt;we have just a handful views and forms rendered by Rails (most are generated with JS);&lt;/li&gt;
&lt;li&gt;REST architecture (we deal with very specific requests rather than generic ones over common
resources, which translates to specialized queries that run very quickly without having to
resort to complicated caching strategies for most cases in order to get fast responses);&lt;/li&gt;
&lt;li&gt;responds_to (most requests will simply respond with JSON);&lt;/li&gt;
&lt;li&gt;Sprockets, also known as the Rails Assets Pipeline (not sure if this holds true after
Rails 5.1 added integration to Webpack);&lt;/li&gt;
&lt;li&gt;generators (I don&amp;#39;t use them for a long time because they aren&amp;#39;t really needed and
it&amp;#39;s pretty quick and easy to add new controllers, models, mailers or tests manually);&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, for a long while I have been wondering how exactly Rails was helping us to build and
maintain our application. The application was already very decoupled from Rails and its code
didn&amp;#39;t rely on ActiveSupport core extensions either. We tried to keep our controllers thin,
although there&amp;#39;s still quite some work to do before we get there.&lt;/p&gt;
&lt;p&gt;On the other side, there were a few times I had trouble trying to debug some weird
problems after upgrading Rails and it was I nightmare when I had to dig into Rails&amp;#39;
source code and I wasted a lot of time in the process, so I did have a compelling
reason to not stick with Rails. There were other parts I disliked in Rails, which
I describe in the next section.&lt;/p&gt;
&lt;h2&gt;The Bad Parts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;can&amp;#39;t upgrade individual parts, it&amp;#39;s all or nothing. If you&amp;#39;re using ActiveRecord, for example
you&amp;#39;re forced to upgrade all Rails parts if you want to upgrade ActiveRecord to get support
for some feature. Or the opposite: you might want to upgrade just the framework to get
ActionCable support for example, but then you&amp;#39;d have to fix all deprecated usage from your
ActiveRecord usage in the process;&lt;/li&gt;
&lt;li&gt;hard to follow code base, when debugging edge cases, which makes it hard to estimate tasks
involving debugging weird issues that happened after upgrading Rails for example;&lt;/li&gt;
&lt;li&gt;buggy streaming support through ActionController::Live (had to work around them many times
after upgrading Rails). Try to read its source to understand how it works and you&amp;#39;ll understand
when I say its implementation is quite complicated;&lt;/li&gt;
&lt;li&gt;occasional dead-locks, specially when ActionController::Live was used. That&amp;#39;s why those few
actions were the first one I moved out of Rails;&lt;/li&gt;
&lt;li&gt;ActiveSupport::Dependencies: implicit autoloading and their problems. You must require full
&lt;code&gt;action_view&lt;/code&gt; even if you only need &lt;code&gt;action_view/helpers/number_helper&lt;/code&gt; for example;&lt;/li&gt;
&lt;li&gt;monkey patches to Ruby core classes and methods pollution (it&amp;#39;s my opinion that libraries
shouldn&amp;#39;t freely patch core Ruby classes except for very exceptional cases such as code
instrumenting, implementing a transparent auto-reloading tool and so on, and should be avoided
whenever possible);&lt;/li&gt;
&lt;li&gt;automatic/transparent params binding (security concerns, I often wrote code such as
&lt;code&gt;param[:text].to_s&lt;/code&gt; because I didn&amp;#39;t want to get a hash or an array when accessing some param
because they were injected by some malicious request taking advantage of Rails automatic
params binding rules);&lt;/li&gt;
&lt;li&gt;slow to boot when compared to other Ruby frameworks (more of a development issue),
spring is not perfect and shouldn&amp;#39;t be required in the first place;&lt;/li&gt;
&lt;li&gt;increased test load time, which is quite noticeable when running individual tests;&lt;/li&gt;
&lt;li&gt;the API documentation is incomplete. The guides are great though, but often I wasted a lot of
time trying to look for the documentation of some parts of the API;&lt;/li&gt;
&lt;li&gt;lack of full understanding of the boot process and requests cycle;&lt;/li&gt;
&lt;li&gt;I won&amp;#39;t get into the many details why I don&amp;#39;t like ActiveRecord because I don&amp;#39;t use it for
several years and it&amp;#39;s not a requirement to use Rails, but if you&amp;#39;re curious
&lt;a href=&quot;/en/articles/ruby-rails/2013-12-18-sequel-is-awesome-and-much-better-than-activerecord&quot;&gt;I wrote an article comparing it to Sequel long ago&lt;/a&gt;. My main annoyance with ActiveRecord is related to
its pooling implementation and its ability to checkout a connection from the pool outside
of a block that would ensure it&amp;#39;s checked in again into the pool;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Good Parts&lt;/h2&gt;
&lt;p&gt;Rails is still great as an entrance framework for beginners (and some experts as well). Here
are the good parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;handles static resources (assets in Rails terminology) bundling and integrates with Webpack
out of the box;&lt;/li&gt;
&lt;li&gt;good safe default HTTP headers;&lt;/li&gt;
&lt;li&gt;CSRF protection by default;&lt;/li&gt;
&lt;li&gt;SQL injection protection in bundled ActiveRecord by default;&lt;/li&gt;
&lt;li&gt;optimizations to traditional web pages through Turbolinks;&lt;/li&gt;
&lt;li&gt;bin/console and great in-site debugging with the &lt;code&gt;web-console&lt;/code&gt; gem bundled by default in
development mode;&lt;/li&gt;
&lt;li&gt;separate configuration per environment (development/production/test) with good defaults;&lt;/li&gt;
&lt;li&gt;e-mail integration;&lt;/li&gt;
&lt;li&gt;jobs integration;&lt;/li&gt;
&lt;li&gt;integrated database migrations;&lt;/li&gt;
&lt;li&gt;great automatic code reloading capabilities in the development environment (as long as you
stick with Rails conventions and don&amp;#39;t specify your dependencies manually);&lt;/li&gt;
&lt;li&gt;fast to boot (when comparing to frameworks in other languages, such as Java);&lt;/li&gt;
&lt;li&gt;awesome guides and huge community to ask your questions and get an answer very quickly;&lt;/li&gt;
&lt;li&gt;great community and available gems for all kind of tasks;&lt;/li&gt;
&lt;li&gt;very much audited by security experts and any discovered issues are quickly fixed and new releases are made available with responsible disclosure;&lt;/li&gt;
&lt;li&gt;Github issues are usually quickly fixed;&lt;/li&gt;
&lt;li&gt;Rails source code has an extensive test coverage;&lt;/li&gt;
&lt;li&gt;provide tons of generators, including test, models, controllers, for those who appreciate them;&lt;/li&gt;
&lt;li&gt;provides great performance-related data in the application&amp;#39;s logs (time spent rendering views
and partials and in the database);&lt;/li&gt;
&lt;li&gt;highly configurable;&lt;/li&gt;
&lt;li&gt;internationalization support;&lt;/li&gt;
&lt;li&gt;helpful view helpers such as number and currency formatting;&lt;/li&gt;
&lt;li&gt;a big team of active maintainers and contributors;&lt;/li&gt;
&lt;li&gt;easy websockets API through ActionCable;&lt;/li&gt;
&lt;li&gt;flexible routing;&lt;/li&gt;
&lt;li&gt;bundles with test runners solutions for both Ruby-land tests and full-feature tests through
Capybara (it still lacks an integrated bundled JavaScript test runner though);&lt;/li&gt;
&lt;li&gt;there are probably many more great features I can&amp;#39;t remember out of my head because I
didn&amp;#39;t use myself such as RESTful resources and so on;&lt;/li&gt;
&lt;li&gt;conventions such as paths organizations help a lot teams with lots of developers and frequent
turnovers, and when hiring new members in general, or when handing the project to someone else
and the like. By knowing Rails conventions, when joining an existing Rails application for the
first time the newcomer will know exactly where to find controllers, models, views, workers,
assets, mailers, tests and so on. It&amp;#39;s also very likely they will be used with many gems
commonly used altogether with Rails.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, Rails is not only a framework but a set of good practices (among a set of questionable
practices that will vary accordingly to each one&amp;#39;s taste) bundled together as well. It&amp;#39;s not
the only solution trying to provide a solid ground for web developers though. Another similar
solution with similar goals seems to be &lt;a href=&quot;http://hanamirb.org/&quot;&gt;Hanami&lt;/a&gt; for example, although
Rails seems to be more mature to me. For example, I find code reloading to be a fundamental part
of developing web applications and Hanami doesn&amp;#39;t seem to provide a very solid solution that would
work across different Ruby implementation such as JRuby for example, accordingly to
&lt;a href=&quot;http://hanamirb.org/guides/projects/code-reloading/&quot;&gt;these docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But overall, I still find Rails to be one of the best available frameworks for developing web
applications. It&amp;#39;s just that for my personal tastes and mindset I&amp;#39;m more aligned to something
like &lt;a href=&quot;http://roda.jeremyevans.net/&quot;&gt;Roda&lt;/a&gt; than to something like Rails but one should
understand the motivations behind one&amp;#39;s decisions in order to figure out by themselves which
solution works best for their own taste rather than expecting some article to tell you what
is the Right Solution &amp;trade;.&lt;/p&gt;
</content:encoded></item><item><title>Feeling alone in the Ruby community and replacing Rails with Roda</title><link>https://rosenfeld.page/articles/ruby-rails/2017_05_01_feeling_alone_in_the_ruby_community_and_replacing_rails_with_roda/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2017_05_01_feeling_alone_in_the_ruby_community_and_replacing_rails_with_roda/</guid><pubDate>Mon, 01 May 2017 14:05:00 GMT</pubDate><content:encoded>&lt;h2&gt;Background - the application size&lt;/h2&gt;
&lt;p&gt;Feel free to skip to the next section if you don&amp;#39;t care about it.&lt;/p&gt;
&lt;p&gt;I recently finished moving a 5 years old Rails application to a custom stack on top of
&lt;a href=&quot;https://github.com/jeremyevans/roda&quot;&gt;Roda&lt;/a&gt; from Jeremy Evans, also the maintainer of
the awesome &lt;a href=&quot;https://github.com/jeremyevans/sequel&quot;&gt;Sequel&lt;/a&gt; ORM. The application is
actually older than that and I&amp;#39;ve been working on it for 6 years. It used to be a Grails
application that was moved from SVN to Git about 7 years ago but I never had access to
the SVN repository so I don&amp;#39;t really know how old this application is. It was completely
migrated from Grails to Rails in 2013. And these days I replaced Rails with Roda but
this time it was painless and only took a few weeks.&lt;/p&gt;
&lt;p&gt;I have some experience with replacing the technology of an existing application without
interrupting the regular development flow and deployment procedures and the only times
I really had to interrupt the services for a little while was the day I replaced MySql
with PostgreSQL and the day I moved the servers from collocation to Google Cloud Platform.&lt;/p&gt;
&lt;p&gt;I may write about what steps I usually follow when changing the stack (I replaced
Sprockets with Webpack a few years ago among, Devise with a custom solution, among many
examples) in another article. But the reason I&amp;#39;m describing this scenario for this article&amp;#39;s
purpose is only so that you have some raw idea about this project size, specially if you
consider it had 0 tests when I joined the company as the sole developer and had to
understand a messy Grails application with tons of JS embedded in GSP pages with functions
comprising hundreds of lines with many many logical branches inside. Years later and
there are still tons of tests lacking, specially in the front-end code and much more to
improve. To give you a better idea, we currently have about 5k lines of Ruby
test code, and 20k lines of other custom (not generated) Ruby code plus 5k lines of
database migrations code. Besides that we have about 11k lines of CoffeeScript code,
6k lines of JS code and 2.5k lines of CoffeeScript tests code. I&amp;#39;m not including any
external libraries in those stats. You have probably noticed already how poor is the
test coverage currently, specially in the front-end. At this point I expect you to
have some raw idea on this project size. It&amp;#39;s not a small project.&lt;/p&gt;
&lt;h2&gt;Why replacing Rails in the first place?&lt;/h2&gt;
&lt;p&gt;Understanding this section is definitely the answer on why I feel alone in the Ruby
community.&lt;/p&gt;
&lt;h3&gt;More background about Rails and the Ruby community&lt;/h3&gt;
&lt;p&gt;Again, feel free to skip this subsection.&lt;/p&gt;
&lt;p&gt;When I was working on my Master thesis (Robotics, Electrical Engineering) I stopped
working with web development for a while and focused on embedded C programming, C++
hard real-time systems and the like. After I finished the Master thesis my first job
was back to Delphi programming. Only in 2007 I moved my job back to web development,
several years later and I only had experience with Perl so far. After a lot of
research I decided for Rails and Ruby, although I have also seriously considered
TurboGears and Django by that time, both using the Python language. I wasn&amp;#39;t worried
by the language by that time as I didn&amp;#39;t know either Ruby or Python and they seemed
similar one to the other. Ultimately I chose Rails because of how it handled database
migrations.&lt;/p&gt;
&lt;p&gt;In 2007, when looking at the alternatives, Rails was very appealing. There were
conventions that would save me a lot of work when starting to work with web
development again, there were generators to help me getting started, great
documentation, it bundled a database migrations framework so that I wouldn&amp;#39;t have
to recreate myself, simple to understand error stack-traces, good defaults for the 
production environment (such as proper 500 and 404 pages), great auto-reloading
of code in the development environment, great logging, awesome testing tools and
integrated to generators, quick boot, custom routes, convention over configuration
and so on.&lt;/p&gt;
&lt;p&gt;Last but not least, a very rich ecosystem with smart
people working on great gems and learning Ruby together and they were all amazing
by its meta-programming capabilities, the possibility of changing core classes
through monkey patches and so on. And since it&amp;#39;s possible, we should use it in
all places we can, right?  Specific-domain-languages (SDL) were used by all
popular gems by that time.  And there wasn&amp;#39;t much fragmentation like in the
Java community. Basically almost anyone writing web applications in Ruby were
writing Rails apps and following its conventions. That allowed the community
to grow fast, with several Rails plugins and projects assuming the application
was running Rails. Most of us have only known Ruby because of Rails, including
myself. This is already enough reason to thank DHH. Rails definitely raised
the bar for other web frameworks.&lt;/p&gt;
&lt;p&gt;As the ecosystem matured, we saw the rise of Rack and more people using what they
called micro-frameworks such as the popular Sinatra, Merb among others. Rails
improved internationalization support in version 2, merged with Merb in version 3,
got Sprockets in version 4 and so on. The assets pipeline were really a thing
when they were introduced in Rails by that time. It was probably the latest really
big change introduced by Rails that really inspired the general web development
scenario.&lt;/p&gt;
&lt;p&gt;In the meantime Ruby has also evolved a lot, providing better unicode support,
adding a new Hash syntax, garbage collecting symbols, improving performance and
getting new great tools such as Bundler. RubyGems got a better API, the Rails
guides got much better and they have a superb documentation on securing web
applications that is accessible to any web developer and not only Rails ones. We
have also seen lots of books and courses teaching the Rails way, as well as many
dedicated blogs, videos, conferences and so on. I don&amp;#39;t remember watching such
a fast growing in any other community until JavaScript got a lot of traction
recently, motivated not only by single page applications which are becoming
more and more common, but also by the creation of Node.js.&lt;/p&gt;
&lt;p&gt;Many more languages have been created or re-discovered recently including Go,
Elixir, Haskell, Scala, Rust and many many more. But up to this day, despite
the existing of symbols and a poor threading model in MRI and lack of proper
support for threaded applications in stdlib, Ruby is still my preferred
general purpose language. That includes web applications. What about Rails?&lt;/p&gt;
&lt;h2&gt;Enough is enough! What&amp;#39;s wrong with Rails?&lt;/h2&gt;
&lt;p&gt;If you guessed performance was the reason, you guessed wrong. For some reason
I don&amp;#39;t quite understand, developers seem to be obsessed by performance even
in scenarios where it doesn&amp;#39;t matter. I never faced server-side performance
issues with Rails. Accordingly to NewRelic most requests would be served by
less than 20ms in the server-side. Even if we could cut those 20ms it
wouldn&amp;#39;t make any difference at all. So, what&amp;#39;s wrong after all?&lt;/p&gt;
&lt;p&gt;There&amp;#39;s nothing wrong with Rails in a fundamental way. It&amp;#39;s a matter of taste in
my case I guess because it&amp;#39;s really hard to find an objective way to explain
why I wasn&amp;#39;t fully satisfied with Rails. You should probably understand that
this article is not about bashing on Rails in any way. It&amp;#39;s a personal point
of view on why I feel like a strange and why it&amp;#39;s not a great feeling.
[&lt;em&gt;Update: after writing this article, I spent some time trying to list the parts
I dislike in Rails and &lt;a href=&quot;2017_05_03_ruby_on_rails_the_bad_and_good_parts&quot;&gt;wrote a dedicated article about it, which you can 
read here&lt;/a&gt;
if you&amp;#39;re curious&lt;/em&gt;]&lt;/p&gt;
&lt;p&gt;To help you understand where I come from, I have never followed the &amp;quot;Rails Way&amp;quot;
if there&amp;#39;s such a thing. I used jQuery when Prototype was the default library,
I used RSpec when test/unit was the default one, I used factories when Rails
teached fixtures, I used Sequel rather than the bundled ActiveRecord, but instead
of Sequel&amp;#39;s migrations I used ActiveRecord&amp;#39;s migration through the
&lt;a href=&quot;https://github.com/rosenfeld/active_record_migrations&quot;&gt;active_record_migrations&lt;/a&gt;
gem. Some years ago I replaced Sprockets with Webpack (which fortunately Rails
just embraced in Rails 5.1 release, while I wasn&amp;#39;t using Rails anymore when it
was released). After some frustration trying to get Devise to work well with
Sequel I decided to replace Devise with a custom solution (previously I had
to customize Devise a lot to make it support our non-traditional integration
for dealing with sign-ins and custom password hashing inherited by the time
it was written in Grails).&lt;/p&gt;
&lt;p&gt;Since we&amp;#39;re talking about a single page application, almost all of the requests
were JSON ones. We didn&amp;#39;t embrace REST, or respond_to, we had very few
server-side views and often had to dig into Rails or Devise source code to try
to understand why something wasn&amp;#39;t working as we expected them to. That included
several problems we had with streamed responses (which Rails calls Live Streaming
for some reason I don&amp;#39;t quite follow, although I suspect that&amp;#39;s because they
introduced some optimizations to start sending the view&amp;#39;s header sooner and called
it streaming support, so they needed another name when they introduced
&lt;code&gt;ActionController::Live&lt;/code&gt;) after each major Rails upgrade. I used to spend a lot
of time trying to understand Rails internal source whenever I had to debug such
problems. It was pretty confusing to me. The same happened with Devise.&lt;/p&gt;
&lt;p&gt;At some point I started to ask myself what Rails was adding to the table. And
it got worse. When I first met Rails it booted in no time. It got slower to
boot at each new release and then they introduced complex solutions such as
spring to try to fix this slowness. For a long time they used (and still use
to this day) Ruby&amp;#39;s &lt;code&gt;autoload&lt;/code&gt; feature to lazily evaluate code as it&amp;#39;s needed
in order to decrease the boot time. Matz don&amp;#39;t like &lt;code&gt;autoload&lt;/code&gt; and I don&amp;#39;t
like it either, but this article is already long enough to discuss this subject
too.&lt;/p&gt;
&lt;p&gt;Something I never particularly enjoyed in Rails was all that magic related to
auto-loading. I always preferred explicit and simple code over sophisticated
code that auto-wires things. As you can guess, even though I loved how
Rails booted quickly and how auto-reloading just worked with Rails (except
when it didn&amp;#39;t - more on that later) I really wanted to specify all my
dependencies explicitly in each file. But I couldn&amp;#39;t just use &lt;code&gt;require&lt;/code&gt; or
auto-reloading would stop working. I had to use ActiveSupport&amp;#39;s
&lt;code&gt;require_dependency&lt;/code&gt; and I hated it because it wasn&amp;#39;t just regular Ruby code.&lt;/p&gt;
&lt;p&gt;I also didn&amp;#39;t like the fact that Rails enforced all monkey patches to Ruby
core classes made by ActiveSupport extensions, introducing methods such as
&lt;code&gt;blank?&lt;/code&gt;, &lt;code&gt;present?&lt;/code&gt;, &lt;code&gt;presence&lt;/code&gt;, &lt;code&gt;try&lt;/code&gt;, &lt;code&gt;starts_with?&lt;/code&gt;, &lt;code&gt;ends_with?&lt;/code&gt; and so on.
That&amp;#39;s related to the fact I enjoy explicit dependencies as I think it&amp;#39;s much
easier to follow a code with explicit dependencies.&lt;/p&gt;
&lt;p&gt;So, one of my main motivations to get rid of Rails was to get rid of
ActiveSupport, since Rails depends on ActiveSupport, including its monkey
patches and auto-loading implementation. Replacing Rails with Roda alone
didn&amp;#39;t allow me to get rid of ActiveSupport just yet as I&amp;#39;ll explain
later in this article, but it was an important first move. What follows
is the kind of frustration with the Ruby community in the sense of how
very popular Ruby gems are written with about the same mentality of those
from Rails core. Such gems include &lt;del&gt;the very popular mail gem as well as&lt;/del&gt;
FactoryGirl, for example. &lt;del&gt;Even Sidekiq will patch Ruby core classes.&lt;/del&gt;
I&amp;#39;ll talk more about this later, but let me introduce Roda first.&lt;/p&gt;
&lt;p&gt;[&lt;em&gt;Update: after writing this article both the mail and sidekiq gems have
worked to remove their monkey patches and I&amp;#39;d like to congratulate them
for the effort and give them &amp;quot;Thank you so much!&amp;quot;&lt;/em&gt;]&lt;/p&gt;
&lt;h2&gt;Why Roda?&lt;/h2&gt;
&lt;p&gt;From time to time I considered replacing Rails with something else but I always
gave up for a reason or another. Sometimes I realized I liked Sprockets and
the other framework didn&amp;#39;t provide an alternative to the Rails Assets Pipeline.
Another time I realized that auto-reloading didn&amp;#39;t work great with the other
framework. Other times I didn&amp;#39;t like the way code was organized with the other
framework. When I read Jeremy&amp;#39;s announcement for Roda, it was just the right
time with the right framework for me.&lt;/p&gt;
&lt;p&gt;I greatly appreciate Jeremy from a long time since getting introduced to Sequel.
He&amp;#39;s a lovely person, who provides awesome and kind support and he&amp;#39;s a great
library designer. Sequel is simply the best ORM I&amp;#39;ve seen so far. Also, I find
it quite simple to follow Sequel&amp;#39;s code base and after looking into Roda&amp;#39;s source
it&amp;#39;s pretty much trivial to follow and understand. It&amp;#39;s basically one simple source
file that handles routing and plugins support and basically everything else is
provided by plugins you can opt-in/out and each plugin, being small and self
contained, is pretty simple to understand and if you don&amp;#39;t agree with how it&amp;#39;s
implemented just implement that part your own.&lt;/p&gt;
&lt;p&gt;After having a glance over the core &lt;a href=&quot;http://roda.jeremyevans.net/documentation.html&quot;&gt;Roda plugins&lt;/a&gt;
one stood out particularly: &lt;a href=&quot;http://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/MultiRun.html&quot;&gt;multi_run&lt;/a&gt;.
For what I want, this plugin would give me great organization, similar to Rails
controllers, with the advantage that they could have their own middleware stacks,
they could be mounted anywhere, including in a separate app, they were easy to
test separately as if they were a single app if desired but more importantly:
it allowed me to easily lazy load the application code, which allowed the
application to boot instantly with Puma, without the need of autoload and other
trickery. Here&amp;#39;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;roda&amp;#39;
module Apps
  class MainApp &amp;lt; Roda
    plugin :multi_run
    # you&amp;#39;ll probably want other plugins, such as :error_handler and :not_found,
    # or maybe error_email

    def self.register_app(path, &amp;amp;app_block)
      -&amp;gt;(env) do
        require_relative path
        app_block[].call env
      end
    end

    run &amp;#39;sessions&amp;#39;, register_app(&amp;#39;sessions_app&amp;#39;){ SessionsApp }
    run &amp;#39;static&amp;#39;, register_app(&amp;#39;static_app&amp;#39;){ StaticApp }
    run &amp;#39;users&amp;#39;, register_app(&amp;#39;users_app&amp;#39;){ UsersApp }
    # and so on
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even if you decide to load the main application when testing particular apps, the
overhead would be negligible, since it would only load the tested app basically.
And if you are afraid of using lazy loading in the production environment because
you want to deliver a warmed app, it&amp;#39;s quite easy to change &lt;code&gt;register_app&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;roda&amp;#39;
module Apps
  class MainApp &amp;lt; Roda
    plugin :multi_run
    plugin :environments

    def self.register_app(path, &amp;amp;app_block)
      if production?
        require_relative path
        app_block[]
      else
        -&amp;gt;(env) do
          require_relative path
          app_block[].call env
        end
      end
    end

    run &amp;#39;sessions&amp;#39;, register_app(&amp;#39;sessions_app&amp;#39;){ SessionsApp }
    # and so on
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not just a theory, this is how I implemented in our application and it
boots in less than a second. Just about the same as the simplest Rack app.
Of course, I hadn&amp;#39;t really measured this in any scientific way, it&amp;#39;s a simple
in-head count when running &lt;code&gt;bundle exec puma&lt;/code&gt;, where most of the time is spent
on Bundler and requiring Roda (about 0.6s with my gemset). No need for &lt;code&gt;spring&lt;/code&gt;,
&lt;code&gt;autoload&lt;/code&gt; or any complicated code to make it fast. It just works and it&amp;#39;s just
Ruby, by using explicit lazy loading rather than an automatic system.&lt;/p&gt;
&lt;p&gt;So, I really wanted to try this approach and I had a plan where I would run
both Roda and Rails stacks altogether for a while, by running the Rails app
as the fallback app when the Roda stack wouldn&amp;#39;t match the route. I could even
use the &lt;a href=&quot;http://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/PathRewriter.html&quot;&gt;path_rewriter&lt;/a&gt;
plugin to migrate a single action at a time to the Roda stack if I wanted to.&lt;/p&gt;
&lt;p&gt;There was just one remaining issue I had to figure out how to solve before
I started moving the app to the Roda stack: automatic code reloading. I
decided to ask in the &lt;code&gt;ruby-roda&lt;/code&gt; mail group how Roda handled code reloading
and Jeremy said it was out of Roda&amp;#39;s responsibility and that I could choose
any code reloader I wanted and pointed to some documentation listing some
of them, including one of his own. I spent quite some time researching about
them and still preferred the one provided by &lt;code&gt;ActiveSupport::Dependencies&lt;/code&gt;
but since I wanted to get rid of ActiveSupport and autoloading in the first
place there was no point in keep using it. If you&amp;#39;re curious about this
research, I wrote about it &lt;a href=&quot;2016_07_18_a_review_of_code_reloaders_for_ruby&quot;&gt;here&lt;/a&gt;.
If you&amp;#39;re curious on why I dislike Ruby&amp;#39;s &lt;code&gt;autoload&lt;/code&gt; feature, you&amp;#39;ll
find the explanation in that article.&lt;/p&gt;
&lt;p&gt;After some discussion around automatic code reloading in Ruby with Jeremy
I suggested him an approach I think would work pretty well and transparently
although it would require to patch both &lt;code&gt;require&lt;/code&gt; and &lt;code&gt;require_relative&lt;/code&gt;
in development mode. Jeremy wasn&amp;#39;t much interested on it because of those
monkey patches, but I was still confident it would be a better option than
the others I had evaluated so far. I decided to give it a try and that&amp;#39;s
how &lt;a href=&quot;2016_07_18_autoreloader_a_transparent_automatic_code_reloader_for_ruby&quot;&gt;AutoReloader was born&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the autoreloading issue solved, it was all set to start porting the
app slowly to the Roda stack, and the process was pretty much a breeze.
If you want to have some basic idea on Rails overhead, the full Ruby specs
suite were about 2s faster with the same (converted) tests after getting rid
of the last Rails bits. It used to take 10s to run 380 examples and thousands
of assertions, and after getting rid of Rails it took 8s with an extra example.
Upgrading Bundler saved me another half a second so currently it takes 7.6s
to finish (about half a second for &lt;code&gt;bundle exec&lt;/code&gt;, 1.5s to load accordingly to
RSpec report and 5.6s to run).&lt;/p&gt;
&lt;p&gt;But getting rid of Rails was just the first step in this lonely journal.&lt;/p&gt;
&lt;h2&gt;Rails is out, what&amp;#39;s next?&lt;/h2&gt;
&lt;p&gt;Getting rid of Rails wasn&amp;#39;t enough to get rid of ActiveSupport. We have a
LocaleUtils class we use to format numbers among other utilities based on
the user&amp;#39;s locale. It used to include &lt;code&gt;ActionView::Helpers::NumberHelper&lt;/code&gt;,
and by that time I learned the hard way that I couldn&amp;#39;t simply
&lt;code&gt;require &amp;#39;action_view/helpers/number_helper&amp;#39;&lt;/code&gt; because I&amp;#39;d have problems
related to ActiveSupport&amp;#39;s autoloading mechanism, so I had to fully
require &lt;code&gt;action_view&lt;/code&gt;. Anyway, since ActionView depends on ActiveSupport
I wanted to get rid of it as well. As usual, after lots of wasted time
searching for Ruby number formatting gems I decided to implement the
formatting myself and a few hours later I got rid of ActionView.&lt;/p&gt;
&lt;p&gt;But ActiveSupport was still there as a great warrior! This time it was
dependency of... guess what? Yep, FactoryGirl! Oh, man :( After some
research on alternative factory implementations I found
&lt;a href=&quot;https://github.com/paulelliott/fabrication/issues&quot;&gt;Fabrication&lt;/a&gt; to be
dependency free. An hour later I ported our factories to Fabrication
and finally got rid of ActiveSupport! Yay, no more monkey patches
to core Ruby classes! Right?&lt;/p&gt;
&lt;p&gt;Well, not exactly... :( The monkey patch culture is deeply rooted in
Ruby&amp;#39;s community. &lt;del&gt;Some very popular gems add monkey patches, such as
the mail gem, or sidekiq.&lt;/del&gt; While reading the mail gem source I found it
very confusing, so I decided to replace it with something simpler.
We use exim4 to forward e-mails to Amazon SES, so Ruby&amp;#39;s basic NET/SMTP
support is enough for delivering e-mails to Exim, all I needed was a
MIME mail formatter in order to send simple TEXT + HTML multi-part
mail to users. After some more research I decided to implement it
myself and this is how &lt;a href=&quot;https://github.com/rosenfeld/simple_mail_builder&quot;&gt;simple_mail_builder&lt;/a&gt;
was born.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;At some point I might decide to create my own simple jobs processor
just to get rid of Sidekiq&amp;#39;s monkey patches, but&lt;/del&gt; my point is that I
have this feeling of being a lonely warrior fighting a lost battle
because of my expectations mismatch with what the Ruby community
overall consider acceptable practices such as modifying Ruby core
classes in libraries. I agree it&amp;#39;s okay for instrumenting code, such
as NewRelic, to patch other&amp;#39;s code, but for other use cases I don&amp;#39;t
really agree with such approach.&lt;/p&gt;
&lt;p&gt;In one hand I really love the Ruby language, except for some few
caveats, but there&amp;#39;s a huge mismatch with the Ruby community way
of writing Ruby code, and this is a big thing. I don&amp;#39;t really know
what&amp;#39;s the situation in other language communities, so I guess I
might be a lonely warrior in any other language I opted for instead
of Ruby, but Ruby is the only language I really appreciate so far
among those I&amp;#39;ve worked with.&lt;/p&gt;
&lt;p&gt;I guess I should just stop dreaming about the ideal Ruby community
and give up on trying to get a monkey-patch free web application...&lt;/p&gt;
&lt;p&gt;At least, I can now easily and happily debug anything that happens
to the application without having to spend a lot of time digging into
Rails or Devise&amp;#39;s source code, which used to take me a lot of time.
Everything&amp;#39;s clean water.  I have tons of flexibility to do what I
want in no time with the new stack. The application boots pretty
quickly and I&amp;#39;ll never run into edge cases involving
ActiveSupport::Dependencies auto-reloading again. Or issues
involving ActionController::Live. Or Devise issues when using
Sequel as the ORM.&lt;/p&gt;
&lt;p&gt;Ultimately I feel like I got full control
over the application and that&amp;#39;s simply priceless! It&amp;#39;s an awesome
feeling of freedom I never experienced before. Instead of focusing
on the lonely warrior fighting a lost battle bad feeling, I&amp;#39;ll try
concentrate on those great benefits from now on.&lt;/p&gt;
</content:encoded></item><item><title>Using RSpec Nested Transactions to speed up tests touching the database</title><link>https://rosenfeld.page/articles/ruby-rails/2016_08_05_using_rspec_nested_transactions_to_speed_up_tests_touching_the_database/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2016_08_05_using_rspec_nested_transactions_to_speed_up_tests_touching_the_database/</guid><pubDate>Fri, 05 Aug 2016 22:24:00 GMT</pubDate><content:encoded>&lt;p&gt;TLDR: This article proposes savepoints to implement nested transactions, which are supported by
PostgreSQL, Oracle, Microsoft SQL Server, MySQL (with InnoDB but I think some statements would
automatically cause an implicit commit, so I&amp;#39;m not sure it works well with MySQL) and other
vendors, but not by some vendors or engines. So, if using savepoints or nested transactions are
not possible with your database most likely this article won&amp;#39;t be useful to you. Also, not all
ORM provide support for savepoints in their API. I know Sequel and ActiveRecord do. It also
provides a link on how to achieve the same goal with Minitest.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been feeling lonely about my take on tests for a long time. I&amp;#39;ve read many articles on tests
in the past years and most of them, not only in the Ruby community, seem to give us the same
advices. Good advices by the way. I understand the reasoning about them but I also understand
they come with trade-offs and this is where I feel kind of lonely. All articles I&amp;#39;ve read and
some people that have worked with me have tried to convince me that I&amp;#39;m just plain wrong.&lt;/p&gt;
&lt;p&gt;I never cared much about this but I never wrote about it either as I thought no one would be
interested in learning about some techniques I&amp;#39;ve been using for quite some years to speed up my
tests. Because it seems everything would simply tell me I&amp;#39;d go to hell for writing tests this way.&lt;/p&gt;
&lt;p&gt;A few weeks ago I read &lt;a href=&quot;http://travisofthenorth.com/blog/2016/6/18/rspec-search-destroy&quot;&gt;this article from Travis Hunter&lt;/a&gt;
which reminded me of an old TO-DO. More importantly, it made me realize I wasn&amp;#39;t that lonely in
thinking the way I do about tests.&lt;/p&gt;
&lt;p&gt;&amp;quot;Bullshit! I came here because the titles said my tests would be faster, I&amp;#39;m not interested
in your long stories!&amp;quot;. Sure, feel free to completely skip the next section and go straight to
the fun section.&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;I graduated in Electrical Engineering after 5 years in the college. Then more two years working
on my master thesis on hard real-time systems towards mobile robotics. I think there are two
things which engineers in general get used to after a few years in the college. Almost everything
involves trade-offs and one of the most important jobs of an engineering is to identify them and
choose the one they consider to have the best cost benefit. The other one is related to the first
one in knowing that some tools will better fit a set of goals. I mean, I know this is also
understood by CS and similar graduated people, but I have this feeling it&amp;#39;s not as strong in
general in those areas as I observe in some (electrical/mechanical/civil) engineers.&lt;/p&gt;
&lt;p&gt;When I started using RSpec and Object Daddy (many of you may only know Factory Girl these days),
a popular factory tool by that time, I noticed my suite would take almost a minute for just a
few examples touching the database. That would certainly slow me down as I would have to add
many more tests.&lt;/p&gt;
&lt;p&gt;But I felt really bad when I complained about that once in the RSpec mailing list and
&lt;a href=&quot;https://groups.google.com/forum/#!searchin/rspec/rodrigo$20rosenfeld$20rosas%7Csort:relevance/rspec/mqHyXhV04A0/rlsicCfJGN0J&quot;&gt;David Chemlinsky mentioned about taking 54s to run a couple of hundred examples&lt;/a&gt;
when actually I had only 54 examples in my suite by that time.&lt;/p&gt;
&lt;p&gt;And it felt even worse when I contributed once to Gitorious and noticed that over a thousand
examples would finish in just a few seconds, even though lots of them didn&amp;#39;t touch the database.
Marius Mathiesen and Christian Johansen are very skilled developers and they were the main
Gitorious maintainers by that time. Christian is the author of the popular Sinon.js, one of
the authors of the great Buster.js and author of the Test-Driven JavaScript Development book.&lt;/p&gt;
&lt;p&gt;For that particular application, I had to create a lot of records in order to create the record
I needed to test. And I was recreating them on every single test requiring such record, through
Object Daddy but I suspect the result would be about the same with FactoryGirl or any other
factory tool.&lt;/p&gt;
&lt;p&gt;When I realized that creating lots of records in the database was that expensive, I stopped
following the traditional advises for writing tests and only worried about what I really cared
for which remains basically the same to these days.&lt;/p&gt;
&lt;p&gt;These are my test goals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ensure my application works (the main goal by far);&lt;/li&gt;
&lt;li&gt;avoid regressions (linked to the previous one);&lt;/li&gt;
&lt;li&gt;the suite should run as fast as possible (just a few seconds if possible);&lt;/li&gt;
&lt;li&gt;it should give me enough confidence to allow me to completely change the implementations
during any refactoring without completely breaking the tests; To me that means avoid mocking
or stubbing objects and performing HTTP requests against a real server for testing things
like cookie-based sessions and a few other scenarios
 (&lt;a href=&quot;https://github.com/rosenfeld/rack_toolkit&quot;&gt;rack_toolkit&lt;/a&gt;
allows me to create such tests while still being fast).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are not my test goals at all:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;writing specs in such a way they would serve as a documentation. I really don&amp;#39;t care how
the output looks like when I run a single test file with RSpec. That&amp;#39;s also the reason why
I never used Cucumber. Worrying about this adds more complexity and I don&amp;#39;t think they are
useful for documentation purposes anyway;&lt;/li&gt;
&lt;li&gt;each example should have a single expectation. I simply don&amp;#39;t see much value on this and
very often this has the potential of slowing down the test suite;&lt;/li&gt;
&lt;li&gt;tests should be independent from each other and ideally we should run them in random order.
I understand the reasoning behind this and I actually find it useful and see value in it. But
if I see trade-offs I&amp;#39;d trade test-independence by speed. Fortunately this is not required
by my tests touching the database using the technique I demonstrate in the next section, but
it may speed up some request tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I even wrote my own JavaScript test runner because I needed one that allowed me to run my
tests in the specified order, supported IE6 (by that time) and beforeAll and I couldn&amp;#39;t find
any by that time. My application used to register some live events on document and would never
unregister them because it was not necessary, so my test suite would only be allowed to
initialize it once. Also, recreating a tree on every test would take a lot of time, so I
wanted to run a set of tests that would work on the same tree based on the result of previous
tests.&lt;/p&gt;
&lt;p&gt;I was okay with that trade as long my tests would run fast, but JavaScript test runners authors
wouldn&amp;#39;t agree, so I created &lt;a href=&quot;https://github.com/rosenfeld/oojspec&quot;&gt;OOJSpec&lt;/a&gt; for my needs. I
never advertised it because I don&amp;#39;t consider it to be feature complete yet, although
it suites my current needs. It doesn&amp;#39;t currently support running a single test because I need
to think in some way to declare a test&amp;#39;s dependencies (in other tests) so that those dependent
tests would also be run before the requested one. Also, maintaining a test runner is not trivial
and since it&amp;#39;s currently hard for me to find time to review patches I preferred not to announce
it. Since I can run individual test files, it&amp;#39;s working fine for my needs, so I don&amp;#39;t currently
have much motivation to further improve it.&lt;/p&gt;
&lt;h2&gt;A fast approach to speed up tests touching the database&lt;/h2&gt;
&lt;p&gt;A common case while testing some scenarios is that one wants to write a set of tests that
exercise about the same set of records. Most people nowadays are using either one of the two
common approaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;creating the records either manually (through the ORM usually) or through factories;&lt;/li&gt;
&lt;li&gt;loading fixtures (which are usually faster than creating them using factories);&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Loading specific fixtures before each context wouldn&amp;#39;t be significantly faster than using
a factory when using a competent factory and ORM implementations, so some will simply use
DatabaseCleaner with the truncate strategy to delete all data before the suite starts and
loading the fixtures to the database. After that usually each example would run inside a
transaction that would be rolled back which is usually much faster than truncating and
reloading the fixtures.&lt;/p&gt;
&lt;p&gt;I don&amp;#39;t particularly like fixtures because I find them to make tests more complicated to write
and understand. But I would certainly consider them if they would make my tests significantly
faster. Also, nothing prevents us from using the same fixtures approach with factories as we
could also use the factories to populate the initial data before the suite starts, but the
real problem is that writing tests would still be more complicated in my opinion.&lt;/p&gt;
&lt;p&gt;So, I prefer to think about solutions that allows tests to remain fast even when using factories.
Obviously that means that we should find some way to avoid recreating the same records for a
given group since the only way to speed up a suite that takes a lot of time creating records
in the database is to reduce the amount of time spent in the database creating those records.&lt;/p&gt;
&lt;p&gt;There are other kind of optimizations that would be interesting to try but that it&amp;#39;s probably
complicated to implement as it would probably require a change in FactoryGirl API to allow
such optimizations. For example, rather than sending one statement at a time to the database
I guess it would be faster to send all of them at once. However I&amp;#39;m not sure it would be that
much faster if you are using a connection pool (usually a single connection in the test
environment) that keeps the connection open and you&amp;#39;re using a local database.&lt;/p&gt;
&lt;p&gt;So, let&amp;#39;s talk about the low-hang fruits which are also the best ones in this case. How can we
reuse a set of records among a set of examples while still allowing them to be independent from
each other?&lt;/p&gt;
&lt;p&gt;The idea is to use nested transactions to achieve that goal. You begin a transaction during
the suite start (or some context involving database statements) and then the suite will
create a savepoint before a set/group of examples (a context in RSpec language) and rollback
to that savepoint after the context finished.&lt;/p&gt;
&lt;p&gt;Managing such savepoint names can be complex to implement on your own but if you are going this
route anyway because your ORM doesn&amp;#39;t provide an easy API to handle nested transactions then
you may not be interested in the rspec_nested_transactions gem I&amp;#39;ll present in the next section.&lt;/p&gt;
&lt;p&gt;However with Sequel this is as easy as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# The :auto_savepoint option will automatically add the &amp;quot;savepoint: true&amp;quot; option to inner
# transaction calls.
DB.transaction(auto_savepoint: true, savepoint: true, rollback: :always){ run_example }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With ActiveRecord the API works like this (thanks Tiago Amaro, for showing me the API):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;ActiveRecord::Base.transaction(requires_new: true) do
  run[]
  raise ActiveRecord::Rollback
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will detect whether a transaction is already in place and use savepoints if it is or will
issue a BEGIN to start the transaction. It will manage the savepoint names automatically for you
and will even rollback it automatically when using the &amp;quot;rollback: :always&amp;quot; option. Very handy
indeed. But in order to achieve this Sequel doesn&amp;#39;t provide methods such as &amp;quot;start_transaction&amp;quot;
and &amp;quot;end_transaction&amp;quot;.&lt;/p&gt;
&lt;p&gt;Why is this a problem? Sequel does the right thing by always requiring a block to be passed to
the &amp;quot;transaction&amp;quot; method but RSpec does not support &amp;quot;around(:all)&amp;quot;. However
&lt;a href=&quot;http://myronmars.to/n/dev-blog/2012/03/building-an-around-hook-using-fibers&quot;&gt;Myron Marston posted a few years ago how to implement it using fibers&lt;/a&gt;
and &lt;a href=&quot;https://github.com/seanwalbran/rspec_around_all&quot;&gt;Sean Walbran created a real gem based on that article&lt;/a&gt;.
You&amp;#39;d probably be interested in combining this with the well known strategy of wrapping each
example in a nested transaction themselves.&lt;/p&gt;
&lt;p&gt;If you feel confident that you will always remember to use &amp;quot;around(:all)&amp;quot; with a
&amp;quot;DB.transaction(savepoint: true, rollback: :always){}&amp;quot; block whenever you want to create such
a common set of records to be used inside a group of examples then the rspec_around_all gem
may be all you need to implement that strategy.&lt;/p&gt;
&lt;p&gt;Not only I find this bug prone (I could forget about the transaction block) I also bother to
repeat this pattern every time I want to create a set of shared records.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s a caveat though. If your application creates transactions itself it should be aware of
savepoints too (this is accomplished automatically when using Sequel provided you use the
:auto_savepoint option in the outmost transaction) even if BEGIN-COMMIT is enough out of the tests,
so that it works as expected in combination with this technique. If you are using ActiveRecord,
that means using &amp;quot;requires_new: true&amp;quot;.&lt;/p&gt;
&lt;p&gt;If you are using Sequel or ActiveRecord and PostgreSQL, Oracle, MSSQL, MySQL (with InnoDB) or
any other vendor supporting nested transactions and have full control over the transaction calls,
implementing this technique can speed up your suite a lot with regards to the tests touching the
database. And rspec_nested_transactions will make it even easier to implement.&lt;/p&gt;
&lt;h2&gt;Let the fun begin: introducing rspec_nested_transactions&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve released today &lt;a href=&quot;https://github.com/rosenfeld/rspec_nested_transactions&quot;&gt;rspec_nested_transactions&lt;/a&gt;
which allows one to run all (inner) examples and contexts inside a transaction (usually a
database transaction) with a single configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;rspec_nested_transactions&amp;#39;

RSpec.configure do |c|
  c.nested_transaction do |example_or_group, run|
    (run[]; next) unless example_or_group.metadata[:db] # or delete this line if you don&amp;#39;t care
    # with Sequel, assuming the database is stored in DB:
    DB.transaction(auto_savepoint: true, savepoint: true, rollback: :always, &amp;amp;run)

    # with ActiveRecord (Oracle, MSSQL, MySql[InnoDB], PostgreSQL):
    ActiveRecord::Base.transaction(requires_new: true) do
      run[]
      raise ActiveRecord::Rollback
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s it. I&amp;#39;ve been using a &lt;a href=&quot;https://github.com/rosenfeld/rspec_around_all/tree/config_around&quot;&gt;fork of rspec_around_all (branch config_around)&lt;/a&gt;
since 2013 and it has always served me great since then and I never had to change it since then,
so I guess it&amp;#39;s quite stable. However for a long time I considered moving it to a separate gem
and remove the parts I didn&amp;#39;t actually use (like &amp;quot;around(:all)&amp;quot;). I always post-poned it but
Travis&amp;#39; article reminded me about it and I thought that maybe others might be interested on this
approach as well.&lt;/p&gt;
&lt;p&gt;So, I improved the specs, cleaned up the code using recent Ruby features (&amp;gt;= 2.0 [prepend]) and
released the new gem. Since the specs use the &amp;quot;&amp;lt;&amp;lt;~&amp;quot; heredoc it will only run on Ruby &amp;gt;= 2.3 but
I guess it should work with all Ruby &amp;gt;= 2.0 (or even 1.9 I guess if you implement Module.prepend).&lt;/p&gt;
&lt;h2&gt;What about Minitest?&lt;/h2&gt;
&lt;p&gt;Jeremy Evans, the Ruby Hero who happens to be the maintainer of &lt;a href=&quot;http://sequel.jeremyevans.net/&quot;&gt;Sequel&lt;/a&gt;
and creator of &lt;a href=&quot;http://roda.jeremyevans.net/&quot;&gt;Roda&lt;/a&gt;, was kind enough to provide a
&lt;a href=&quot;http://sequel.jeremyevans.net/rdoc/files/doc/testing_rdoc.html#label-Transactional+testing+with+savepoints&quot;&gt;link on how to achieve the save with Minitest&lt;/a&gt;)
in the comments below. No need for Fibers in that case. Go check that out if you&amp;#39;re working with
Minitest.&lt;/p&gt;
&lt;h2&gt;Final notes&lt;/h2&gt;
&lt;p&gt;Currently our application runs 364 examples (RSpec doesn&amp;#39;t report the expectations count, but I
suspect it could be around a thousand) in 7.8s while many of them will touch the database.
Also, when I started this Rails application I decided to give ActiveRecord another try since it
had also included support for a lazy API when Arel was introduced, which I was already used to
with Sequel. A week or two later I decided to move to Sequel after finding AR API quite limiting
for the application&amp;#39;s needs. At that time I noticed that the tests finished considerably faster
after switching from ActiveRecord to Sequel, so I guess Sequel has a lower overhead when compared
to ActiveRecord and switching to Sequel could possibly help speeding up your test suite as well.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s it, I hope some of you would see value in this approach. If you have other suggestions
(besides running the examples in parallel) to speed up a test suite, I&amp;#39;m always interested in
speeding up our suite. We have a ton of code both in server-side and client-side and only part
of them is currently tested and I&amp;#39;m always looking towards improving the test coverage which
means potentially we could implement over 500 more tests (for both server-side and client-side)
while I still want the test suite to complete in just a few seconds. I think the most
hard/critical parts are currently covered in the server-side and it will be easier to test other
parts once I&amp;#39;m moving the application to Roda (the client-side needs much more work to make
it easier to test some critical parts). I would be really happy if both server and client-side
suites would finish in within a second ;) (currently the client-side suite takes about 11s to
complete - 204 tests / 438 assertions).&lt;/p&gt;
</content:encoded></item><item><title>Introducing RackToolkit: a fast server and DSL designed to test Rack apps</title><link>https://rosenfeld.page/articles/ruby-rails/2016_07_27_introducing_racktoolkit_a_fast_server_and_dsl_designed_to_test_rack_apps/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2016_07_27_introducing_racktoolkit_a_fast_server_and_dsl_designed_to_test_rack_apps/</guid><pubDate>Wed, 27 Jul 2016 18:43:00 GMT</pubDate><content:encoded>&lt;p&gt;I started to experiment with writing big Ruby web applications as a set of smaller and fast
Rack applications connected by a router using
&lt;a href=&quot;http://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/MultiRun.html&quot;&gt;Roda&amp;#39;s multi_run plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Such design allows the application to boot super fast in the development environment (and in
the production environment too unless you prefer to eager load your code in production).
Here&amp;#39;s how the design looks like (&lt;a href=&quot;/en/articles/ruby-rails/2016-07-18-autoreloader-a-transparent-automatic-code-reloader-for-ruby&quot;&gt;I&amp;#39;ve written about AutoReloader in another article&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# config.ru
if ENV[&amp;#39;RACK_ENV&amp;#39;] == &amp;#39;development&amp;#39;
  require &amp;#39;auto_reloader&amp;#39;
  AutoReloader.activate reloadable_paths: [ &amp;#39;apps&amp;#39;, &amp;#39;lib&amp;#39;, &amp;#39;models&amp;#39; ]
  run -&amp;gt;(env) do
    AutoReloader.reload! do
      ActiveSupport::Dependencies.clear # avoid some issues
      require_relative &amp;#39;apps/main&amp;#39;
      Apps::Main.call env
    end
  end
else
  require_relative &amp;#39;apps/main&amp;#39;
  run Apps::Main
end

# apps/main.rb
require &amp;#39;roda&amp;#39;
module Apps
  class Main &amp;lt; Roda
    plugin :multi_run
    # other plugins and middlewares are added, such as :error_handler, :not_found, :environments
    # and a logger middleware. They take some space, so I&amp;#39;m skipping them.

    def self.register_app(path, &amp;amp;app_block)
      # if you want to eager load files in production you&amp;#39;d change this method a bit
      -&amp;gt;(env) do
        require_relative path
        app_block[].call env
      end
    end

    run &amp;#39;sessions&amp;#39;, register_app(&amp;#39;session&amp;#39;){ Session }
    run &amp;#39;admin&amp;#39;, register_app(&amp;#39;admin&amp;#39;) { Admin }
    # other apps
  end
end

# apps/base.rb
require &amp;#39;roda&amp;#39;
module Apps
  class Base &amp;lt; Roda
    # add common plugins for rendering, CSRF protection, middlewares
    # like ETag, authentication and so on. Most apps would inherit from this.
    route{|r| process r }
    private
    def process(r)
      protect_from_csrf # added by some CSRF plugin
    end
  end
end

# apps/admin.rb
require_relative &amp;#39;base&amp;#39;
module Apps
  class Admin &amp;lt; Base
    private
    def process(r)
      super # protects from forgery and so on
      r.get(&amp;#39;/&amp;#39;){ &amp;quot;TODO Admin interface&amp;quot; }
      # ...
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I want to be able to test those applications separately and for some of them I would only
get confidence if I tested against a real server since I would want them to handle with cookies
or streaming and checking for some HTTP headers injected by the real server and so on. And I
wanted to be able to write such tests that could run as quickly as possible.&lt;/p&gt;
&lt;p&gt;I started experimenting with Puma and noticed it can start a new server really fast (like 1ms
in my development environment). I didn&amp;#39;t want to add many dependencies so I decided to create
some simple DSL over &amp;#39;net/http&amp;#39; stdlib since its API is not much friendly. The only dependencies
so far are &lt;em&gt;http-cookie&lt;/em&gt; and Puma (WEBrick does not support full hijack support and it doesn&amp;#39;t
provide a simple API to serve Rack apps either and it&amp;#39;s much slower to boot). Handling cookies
correctly to keep the user session is not trivial so I decided to introduce the &lt;em&gt;http-cookie&lt;/em&gt;
dependency to manage a cookie jar.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s how &lt;a href=&quot;https://github.com/rosenfeld/rack_toolkit&quot;&gt;rack_toolkit&lt;/a&gt; was born.&lt;/p&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;This way I can start the server before the test suite starts, change the Rack app served by
the server dynamically, and stop it when the suite finishes (or you can simply start and
stop it for each example since it boots really fast). Here&amp;#39;s a spec_helper.rb you could
use if you are using RSpec:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# spec/spec_helper.rb
require &amp;#39;rack_toolkit&amp;#39;
RSpec.configure do |c|
  c.add_setting :server
  c.add_setting :skip_reset_before_example

  c.before(:suite) do
    c.server = RackToolkit::Server.new start: true
    c.skip_reset_before_example = false
  end

  c.after(:suite) do
    c.server.stop
  end

  c.before(:context){ @server = c.server }
  c.before(:example) do
    @server = c.server
    @server.reset_session! unless c.skip_reset_before_example
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Testing the Admin app should be easy now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# spec/apps/admin_spec.rb
require_relative &amp;#39;../../apps/admin&amp;#39;
RSpec.describe Admin do
  before(:all){ @server.app = Admin }
  it &amp;#39;shows an expected main page&amp;#39; do
    @server.get &amp;#39;/&amp;#39;
    expect(@server.last_response.body).to eq &amp;#39;TODO Admin interface&amp;#39;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please take a look at the &lt;a href=&quot;https://github.com/rosenfeld/rack_toolkit&quot;&gt;project&amp;#39;s README&lt;/a&gt; for
more examples and supported API. RackToolkit allows you to get the current_path, referer,
manages cookies sessions, provides a DSL for get, post and post_data on top of &amp;#39;net/http&amp;#39;
from stdlib, allows overriding the environment variables sent to the Rack app, simulating
an https request as if the app was behind some proxy like Nginx, supports &amp;quot;virtual hosts&amp;quot;,
default domain, performing requests to external Internet urls and many other options.&lt;/p&gt;
&lt;h2&gt;Future development&lt;/h2&gt;
&lt;p&gt;It currently doesn&amp;#39;t provide a DSL for quickly access elements from the response body,
filling in forms and submitting them, but I plan to work on this once I need it. It won&amp;#39;t
ever support JavaScript though unless it would be possible at some point to do so without
slowing it down significantly. If you want to work on such DSL, please let me know.&lt;/p&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;The test suite currently runs 33 requests and finishes in ~50ms (skipping the external
request example). It&amp;#39;s that fast.&lt;/p&gt;
&lt;h2&gt;Feedback&lt;/h2&gt;
&lt;p&gt;Looking forward your suggestions to improve it. Your feedback is very welcomed.&lt;/p&gt;
</content:encoded></item><item><title>AutoReloader: a transparent automatic code reloader for Ruby</title><link>https://rosenfeld.page/articles/ruby-rails/2016_07_18_autoreloader_a_transparent_automatic_code_reloader_for_ruby/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2016_07_18_autoreloader_a_transparent_automatic_code_reloader_for_ruby/</guid><pubDate>Mon, 18 Jul 2016 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#39;ve been writing some &lt;a href=&quot;http://roda.jeremyevans.net/&quot;&gt;Roda&lt;/a&gt; apps recently. Roda doesn&amp;#39;t come
with any automatic code reloader, like Rails does. Its README lists quite a few code reloaders
that could be used with Roda but while converting a JRuby on Rails small application to Roda
I noticed I didn&amp;#39;t really like any of the options. I&amp;#39;ve
&lt;a href=&quot;2016_07_18_a_review_of_code_reloaders_for_ruby&quot;&gt;written a review about the available options&lt;/a&gt;
if you&amp;#39;re curious.&lt;/p&gt;
&lt;p&gt;I could simply use ActiveSupport::Dependencies since I knew it was easy to set up and worked
mostly fine but one of the reasons I&amp;#39;m thinking about leaving Rails is the autoloading behavior
of ActiveSupport::Dependencies and the monkey patches to Ruby core classes added by ActiveSupport
as a whole. So, I decided to create &lt;a href=&quot;https://github.com/rosenfeld/auto_reloader&quot;&gt;auto_reloader&lt;/a&gt;
which provides the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;just like Rack::Reloader it works transparently. Just use &amp;quot;require&amp;quot; and &amp;quot;require_relative&amp;quot;.
To automatically track constants definitions one has to override them anyway and I can&amp;#39;t think of
any reliable way to track top-level constants automatically without overriding those methods.
However those methods are only overridden when AutoReloader is activated, which doesn&amp;#39;t happen
in the production environment as it does with ActiveSupport::Dependencies. Those are the only
monkey patches happening in development mode;&lt;/li&gt;
&lt;li&gt;differently from Rack::Reloader, it will detect new top-level constants defined after a
request and unload them upon reloading, preventing several issues caused by not doing that;&lt;/li&gt;
&lt;li&gt;no monkey patches to core Ruby classes in production mode;&lt;/li&gt;
&lt;li&gt;it can use the &amp;#39;listen&amp;#39; gem as a file watcher to speed up the request when no reloadable
files have been changed, in which case the application would respond almost as fast as in
production environments, which is important when we are working on performance optimizations.
It will use &amp;#39;listen&amp;#39; by default when available but it can be opted out and it won&amp;#39;t make much
difference unless, maybe, if some request would load many reloadable files;&lt;/li&gt;
&lt;li&gt;it&amp;#39;s also possible to force reloading even if no loaded files have been changed. This could
be useful if such files would load some non-Ruby configuration files and they have changed but
the README provides another alternative to better handle those cases by using Listen to watch
them and call AutoReloader.force_next_reload;&lt;/li&gt;
&lt;li&gt;it doesn&amp;#39;t provide autoloading like ActiveSupport::Dependencies does;&lt;/li&gt;
&lt;li&gt;it&amp;#39;s possible to configure a minimal delay time between two code reloading procedures;&lt;/li&gt;
&lt;li&gt;it unloads all reloadable files rather than only the changed files as I believe this is a
safer approach and the one also used by ActiveSupport::Dependencies;&lt;/li&gt;
&lt;li&gt;reloadable files are those found in one of the reloadable_paths option provided to
AutoReloader;&lt;/li&gt;
&lt;li&gt;not specific to Rack application, but could be used with any Ruby application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What AutoReloader does not implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;autoloading of files on missing constants. Use Ruby&amp;#39;s &amp;quot;autoload&amp;quot; for that if you want;&lt;/li&gt;
&lt;li&gt;it doesn&amp;#39;t provide a hook system to notify when some file is loaded like
ActiveSupport::Dependencies does;&lt;/li&gt;
&lt;li&gt;it doesn&amp;#39;t provide an option to specify load-once files. An option would be to place them in
different directories and do not include them in the reloadable_paths option;&lt;/li&gt;
&lt;li&gt;it doesn&amp;#39;t reload on changes to files other than the loaded ones, like JSON or YAML
configuration files, but it&amp;#39;s easy to set up them as explained in the project&amp;#39;s README.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Usage with a Rack application&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# app.rb
App = -&amp;gt; { [ &amp;#39;200&amp;#39;, { &amp;#39;Content-Type&amp;#39; =&amp;gt; &amp;#39;text/plain&amp;#39; }, [ &amp;#39;Sample output&amp;#39; ] ] }

# config.ru
if ENV[&amp;#39;RACK_ENV&amp;#39;] != &amp;#39;development&amp;#39;
  require_relative &amp;#39;app&amp;#39;
  run App
else
  require &amp;#39;auto_reloader&amp;#39;
  # won&amp;#39;t reload before 1s elapsed since last reload by default. It can be overridden
  # in the reload! call below
  AutoReloader.activate reloadable_paths: [ &amp;#39;.&amp;#39; ]
  run -&amp;gt; (env) {
    AutoReloader.reload! do
      require_relative &amp;#39;app&amp;#39;
      App.call env
    end
  }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you also want it to reload if the &amp;quot;app.json&amp;quot; configuration file has changed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# app.rb
require &amp;#39;json&amp;#39;
config = JSON.parse File.read &amp;#39;config/app.json&amp;#39;
App = -&amp;gt; { [ &amp;#39;200&amp;#39;, { &amp;#39;Content-Type&amp;#39; =&amp;gt; &amp;#39;text/plain&amp;#39; }, [ config[&amp;#39;output&amp;#39;] ] ] }

# append this to config.ru
require &amp;#39;listen&amp;#39; # add the &amp;#39;listen&amp;#39; gem to your Gemfile
app_config = File.expand_path &amp;#39;config/app.json&amp;#39;
Listen.to(File.expand_path &amp;#39;config&amp;#39;) do |added, modified, removed|
  AutoReloader.force_next_reload if (added + modified + removed).include?(app_config)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you decided to give it a try and found any bugs please let me know.&lt;/p&gt;
</content:encoded></item><item><title>A Review of Code Reloaders for Ruby</title><link>https://rosenfeld.page/articles/ruby-rails/2016_07_18_a_review_of_code_reloaders_for_ruby/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2016_07_18_a_review_of_code_reloaders_for_ruby/</guid><pubDate>Mon, 18 Jul 2016 13:59:00 GMT</pubDate><content:encoded>&lt;p&gt;When we are writing a service in Ruby, it&amp;#39;s super useful to have the ability to automatically
change its behavior to conform the latest changes to the code. Otherwise we&amp;#39;d have to manually
restart the server after each change. This would slow down a lot the development flow, specially
if the application takes a while before it&amp;#39;s ready to process next request.&lt;/p&gt;
&lt;p&gt;I guess most people using Ruby are writing web applications with Rails. Many don&amp;#39;t notice that
Rails supports auto code reloading out of the box, through ActiveSupport::Dependencies. A few
will notice it once they are affected by some corner case where the automatic code reloading
doesn&amp;#39;t work well.&lt;/p&gt;
&lt;p&gt;Another feature provided by Rails is the ability of automatic loading files if the application
follows some conventions, so that the developer is not forced to manually require some code&amp;#39;s
dependencies. Another benefit is that this behavior is similar to Ruby&amp;#39;s
&lt;a href=&quot;http://ruby-doc.org/core-2.1.0/Module.html#method-i-autoload&quot;&gt;autoload&lt;/a&gt; feature, which purpose
is to speed up the loading time of applications by avoiding to load files the application won&amp;#39;t
need. Matz seems to dislike this feature and &lt;a href=&quot;https://bugs.ruby-lang.org/issues/5653&quot;&gt;discouraged&lt;/a&gt;
its usage 4 years ago. Personally I&amp;#39;d love to see autoload gone as it can cause bugs that are
hard to track. However, loading many files in Ruby is currently slow even if simply loading them
from disk would be pretty fast. So, I guess Ruby would have to provide some sort of pre-compiled
files support before deprecating autoload so that we wouldn&amp;#39;t need it for the purpose of speeding
up the start-up time.&lt;/p&gt;
&lt;p&gt;Since automatic code reloading usually works well enough for Rails applications, most people
won&amp;#39;t research about code reloaders until they are writing web apps with other frameworks
such as Sinatra, Padrino, Roda, pure Rack, whatever.&lt;/p&gt;
&lt;p&gt;This article will review generic automatic code reloaders, including ActiveSupport::Dependencies,
but leaving specific ones out of the scope, like Sinatra::Reloader and Padrino::Reloader. I&amp;#39;ve
not checked Ruby version compatibility of each one, but all of them work on latest MRI.&lt;/p&gt;
&lt;h2&gt;Rack::Reloader&lt;/h2&gt;
&lt;p&gt;Rack::Reloader is bundled with the rack gem. It&amp;#39;s very simple but it&amp;#39;s only suitable for simple
applications in my opinion. It won&amp;#39;t unload constants, so if you remove some file or rename some
class the old ones will still be available. It works as a Rack middleware.&lt;/p&gt;
&lt;p&gt;One can provide the middleware a custom or external back-end, but I&amp;#39;ll only discuss the default
one, which is bundled with Rack::Reloader, called Rack::Reloader::Stat.&lt;/p&gt;
&lt;p&gt;Before each request it traverse $LOADED_FEATURES, skipping .so/bundle files and call Kernel.load
on each file that has been modified since the last request. Since config.ru is loaded rather than
required it&amp;#39;s not listed in $LOADED_FEATURES so it will be never reloaded. This means that the
app&amp;#39;s code should live in another file required in config.ru rather than living directly in
config.ru. It worth mentioning that because I&amp;#39;ve been bitten by this more than once while testing
Rack::Reloader.&lt;/p&gt;
&lt;p&gt;Differently from the Rails approach, any changed file will be reloaded even if you modify some
gem&amp;#39;s source.&lt;/p&gt;
&lt;h3&gt;Rack::Reloader issues&lt;/h3&gt;
&lt;p&gt;I won&amp;#39;t discuss performance issues when there are many files loaded because one could provide
another back-end able to track files changes very quickly and because there are more important
issues affecting this strategy.&lt;/p&gt;
&lt;p&gt;Suppose your application has some code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;singleton&amp;#39;
class MyClass
  include Singleton
  attr_reader :my_flag
  def initialize
    @my_flag = false
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling MyClass.instance.my_flag will return false. Now, if you change the code so that @my_flag
is assigned to true in &amp;quot;initialize&amp;quot; MyClass.instance.my_flag will still return false.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s investigate another example where Rack::Reloader strategy won&amp;#39;t work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# assets_processor.rb
class AssetsProcessor
  @@processors = []
  def self.register
    @@processors &amp;lt;&amp;lt; self
  end

  def self.process
    @@processors.each :&amp;amp;do_process
  end
end

# assets_compiler.rb
require_relative &amp;#39;assets_processor&amp;#39;
class AssetsCompiler &amp;lt; AssetsProcessor
  register
  
  def self.do_process
    puts &amp;#39;compiling assets&amp;#39;
  end
end

# gzip_assets.rb
require_relative &amp;#39;assets_processor&amp;#39;
class GzipAssets &amp;lt; AssetsProcessor
  register
  
  def self.do_process
    puts &amp;#39;gzipping assets&amp;#39;
  end
end

# app.rb
require_relative &amp;#39;assets_compiler&amp;#39;
require_relative &amp;#39;gzip_assets&amp;#39;
class App
  def run
    AssetsProcessor.process
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running App.new.run will print &amp;quot;compiling assets&amp;quot; and then &amp;quot;gzipping assets&amp;quot;. Now, if you change
assets_compiler.rb, it will also print &amp;quot;compiling assets&amp;quot; once more the next time it&amp;#39;s called.&lt;/p&gt;
&lt;p&gt;This applies to all situations where a given class method is supposed to be run only once or when
the order of files load matter. For example, suppose AssetsProcessor.register implementation is
changed in assets_processor.rb. Since register was already called in its subclasses that means
the change won&amp;#39;t take effect in them since only assets_processor.rb will be reloaded by
Rack::Reloader. Other reloaders discussed here also suffer with this issue but they provide some
work-arounds for some of them.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://github.com/alexch/rerun&quot;&gt;rerun&lt;/a&gt; and &lt;a href=&quot;https://github.com/rtomayko/shotgun&quot;&gt;shotgun&lt;/a&gt;: the reload everything approach&lt;/h2&gt;
&lt;p&gt;Some reloaders like rerun and shotgun will simply reload everything on each request. They fork
at each request before requiring any files, which means those files are never required in the
main process. Due to forking it won&amp;#39;t work on JRuby or Windows. This is a safe approach when
using MRI on Linux or Mac though. However, if your application takes a long time to boot then
your requests would have a big latency during the development mode. In that case, if the reason
for the slow start-up lies in the framework code and other external libraries rather than the
app specific code, which we want to be reloadable, one can require them before forking to speed
it up.&lt;/p&gt;
&lt;p&gt;This approach is a safe bet, but unsuitable when running on JRuby or Windows. Also if loading
all app&amp;#39;s specific code is still slow, one may be interested in looking for faster alternatives.
Besides that, this latency will exist in development mode for all requests even if no files have
been changed. If you&amp;#39;re working on performance improvements other approaches will yield to better
results.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://github.com/jeremyevans/rack-unreloader&quot;&gt;rack-unreloader&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;rack-unreloader&lt;/em&gt; takes care of unloading constants during reload, differently from Rack::Reloader.&lt;/p&gt;
&lt;p&gt;It has basically two modes of operation. One can use &amp;quot;Unreloader.require(&amp;#39;dep&amp;#39;){[&amp;#39;Dep&amp;#39;, ...]}&amp;quot; to
require dependencies while also providing which new constants are created and those will be
unloaded during reload. This is the safest approach but it&amp;#39;s not transparent. For every required
reloadable file we must manually provide a list of constants to be unloaded. On the other side
this is the fastest possible approach since the reloader doesn&amp;#39;t have to try to figure out those
constants automatically, like other options that will be mentioned below do. Also, it doesn&amp;#39;t
override &amp;quot;require&amp;quot;, so it&amp;#39;s great for those that don&amp;#39;t want any monkey patching. Ruby currently
does not provide a way to safely discover those constants automatically without monkey patching
require, so rack-unreloader is probably the best you can get if you want to avoid monkey patches.&lt;/p&gt;
&lt;p&gt;The second mode of operation is to not provide that block and Unreloader will look at changes to
$LOADED_FEATURES before and after the call of Unreloader.require to figure out which constants
the required file define. However, without monkey patching &amp;quot;require&amp;quot; this mode can&amp;#39;t be reliable,
as I&amp;#39;ll explain in the sub-section below.&lt;/p&gt;
&lt;p&gt;Before getting into it, there&amp;#39;s another feature of &lt;em&gt;rack-unreloader&lt;/em&gt; that speed up reloading by
only reloading the changed files, differently from other options I&amp;#39;ll explore below in this
article. However, reloading just changed files is not always reliable as I&amp;#39;ve discussed in the
Rack::Reloader Issues section.&lt;/p&gt;
&lt;p&gt;Finally, differently from other libraries, &lt;em&gt;rack-unreloader&lt;/em&gt; actually calls &amp;quot;require&amp;quot; rather
than &amp;quot;load&amp;quot; and deletes the reloaded files from $LOADED_FEATURES before the request so that
calling &amp;quot;require&amp;quot; will actually reload the file.&lt;/p&gt;
&lt;h3&gt;&lt;em&gt;rack-unlreloader&lt;/em&gt; Issues&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s only reliable if you always provide the constants defined on each Unreloader.require() call.
This is also the fastest approach. It may be a bit boring to write code like this. Also, even in
this mode, it&amp;#39;s only reliable if your application works fine regardless of the order each file
is reloaded (I&amp;#39;ve shown an example in the Rack::Reloader Issues section demonstrating how this
approach is not reliable if this is not the case).&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s explore why the automatic approach is not reliable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# t.rb:
require &amp;#39;json&amp;#39;
module T
  def self.call(json)
    JSON.parse(json)
  end
end

# app.rb:
require &amp;#39;rack/unreloader&amp;#39;
require &amp;#39;fileutils&amp;#39;
Unreloader = Rack::Unreloader.new{ T }
Unreloader.require(&amp;#39;./t.rb&amp;#39;) # {&amp;#39;T&amp;#39;} # providing the block wouldn&amp;#39;t trigger the error
Unreloader.call &amp;#39;{}&amp;#39;
FileUtils.touch &amp;#39;t.rb&amp;#39; # force file to be reloaded
sleep 1 # there&amp;#39;s a default cooltime delay of 1s before next reload
Unreloader.call &amp;#39;{}&amp;#39; # NameError: unitialized constant T::JSON
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;em&gt;rack-unreloader&lt;/em&gt; does not override &amp;quot;require&amp;quot; it can&amp;#39;t track which files define which
constants in a reliable way. So, it thinks &amp;#39;t.rb&amp;#39; is responsible for defining JSON and will then
unload JSON (which has some C extensions which cannot be unloaded). This also affects JRuby if
the file imports some Java package among other similar cases. So, if you want to work with
the automatic approach with &lt;em&gt;rack-unreloader&lt;/em&gt; you&amp;#39;d have to require all those dependencies
before running Unreloader.call. This is very error-prone, that&amp;#39;s why I think it&amp;#39;s mostly useful
if you always provide the list of constants expected to be defined by the required dependency.&lt;/p&gt;
&lt;p&gt;However &lt;em&gt;rack-unreloader&lt;/em&gt; provides a few options like &amp;quot;record_dependency&amp;quot;, &amp;quot;subclasses&amp;quot; and
&amp;quot;record_split_class&amp;quot; to make it easier to specify the explicit dependencies between files so
that the right files are reloaded. But that means the application author must have a good
understanding on how auto-reloading works, how their dependencies work and will also require them
to fully specify the dependencies. It can be a lot of work but it may worth in the case reloading
all reloadable files can take a lot of time. If you&amp;#39;re looking for the fastest possible reloader
than &lt;em&gt;rack-unreloader&lt;/em&gt; may well be your best option.&lt;/p&gt;
&lt;h2&gt;ActiveSupport::Dependencies&lt;/h2&gt;
&lt;p&gt;Now we&amp;#39;re talking about the reloader behind Rails, which is great and battle tested and one of
my favorites. Some people don&amp;#39;t realize it&amp;#39;s pretty simple to use it outside Rails, so let me
demonstrate how it can be used since it seems it&amp;#39;s not widely documented.&lt;/p&gt;
&lt;h3&gt;Usage&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;active_support&amp;#39; # this must be required before any other AS module as per documentation
require &amp;#39;active_support/dependencies&amp;#39;
ActiveSupport::Dependencies.mechanism = :load # or :require in production environment
ActiveSupport::Dependencies.autoload_paths = [__dir__]

require_dependency &amp;#39;app&amp;#39; # optional if app.rb defines App, since it also supports autoloading
puts App::VERSION
# change version number and then:
ActiveSupport::Dependencies.clear
require_dependency &amp;#39;app&amp;#39;
puts App::VERSION
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, in the context of a Rack app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;active_support&amp;#39;
require &amp;#39;active_support/dependencies&amp;#39;
if ENV[&amp;#39;RACK_ENV&amp;#39;] == &amp;#39;development&amp;#39;
  ActiveSupport::Dependencies.mechanism = :load
  ActiveSupport::Dependencies.autoload_paths = [__dir__]

  run -&amp;gt;(env){
    ActiveSupport::Dependencies.clear
    App.call env
  }
else
  ActiveSupport::Dependencies.mechanism = :require
  require_relative &amp;#39;app&amp;#39;
  run App
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;How it works&lt;/h3&gt;
&lt;p&gt;ActiveSupport::Dependencies has a quite complex implementation and I don&amp;#39;t really have a solid
understanding of it so please let me know about my mistakes in the comments section so that I
can fix them.&lt;/p&gt;
&lt;p&gt;Basically it will load dependencies in the autoload_paths or require them depending on the
informed mechanism. It keeps track of which constants are added by overriding &amp;quot;require&amp;quot;. This
way it knows that JSON was actually defined by &amp;quot;require &amp;#39;json&amp;#39;&amp;quot; if it&amp;#39;s called by
&amp;quot;require_dependency &amp;#39;t&amp;#39;&amp;quot; and would detect that T was the new constant defined by &amp;#39;t.rb&amp;#39; and the
one that should be unloaded upon ActiveSupport::Dependencies.clear. Also, it doesn&amp;#39;t reload
individual changed files only but unloads all reloadable files on &amp;quot;clear&amp;quot;. This is less likely
to cause problems as I&amp;#39;ve explained in previous section. It&amp;#39;s also possible to configure it to
use an efficient file watcher, like the one implemented by the &amp;#39;listen&amp;#39; gem, which uses an
evented approach using OS provided system calls. This way, one can skip the &amp;quot;clear&amp;quot; call if
the loaded reloadable files have not been changed by speeding up the request even in development
mode.&lt;/p&gt;
&lt;p&gt;ActiveSupport::Dependencies supports a hooks system that allow others to observe when some
files are loaded and take some action. This is specially useful for Rails engines when you
want to run some code only after some dependency has been loaded for example.&lt;/p&gt;
&lt;p&gt;ActiveSupport::Dependencies is not only a code reloader but it also implements an auto code
loader by overriding Object&amp;#39;s const_missing to automatically try to require code that would
define that constant by following some conventions. For example, in the first time one attempts
to use ApplicationController, since it&amp;#39;s not defined, it will look in the search paths for
an &amp;#39;application_controller.rb&amp;#39; file and load it. That means the start-up time can be improved
since we only load code we actually use. However this could lead to some issues that would make
the application behave differently in production due to side effects caused by the order some
files would be loaded. But Rails applications have been built around this strategy for several
years and it seems such caveats have only affected a few people. Those cases can usually be
worked around through &amp;quot;require_dependency&amp;quot;.&lt;/p&gt;
&lt;p&gt;If your code doesn&amp;#39;t follow the naming convention it will have to use &amp;quot;require_dependency&amp;quot;.
This way, if ApplicationController is defined in controllers/application.rb, you&amp;#39;d use
&amp;quot;require_dependency &amp;#39;controllers/application&amp;#39;&amp;quot; before using it.&lt;/p&gt;
&lt;h4&gt;Why I don&amp;#39;t like autoload&lt;/h4&gt;
&lt;p&gt;Personally I don&amp;#39;t like autoloading in general and always prefer explicit dependencies in all
my Ruby files, so even in my Rails apps I don&amp;#39;t rely on autoloading for my own classes. The
same applies for Ruby&amp;#39;s built-in &amp;quot;autoload&amp;quot; feature. I&amp;#39;ve been bitten already by an autoload
related bug when trying to use ActionView&amp;#39;s number helpers by requiring the specific file I
was interested in. Here&amp;#39;s a simpler use case demonstrating the issue with &amp;quot;autoload&amp;quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# test.rb
autoload :A, &amp;#39;a&amp;#39;
require &amp;#39;a/b&amp;#39;

# a.rb
require &amp;#39;a/b&amp;#39;

# a/b.rb
module A
  module B
  end
end

# ruby -I . test.rb
# causes &amp;quot;...b.rb:1:in `&amp;lt;top (required)&amp;gt;&amp;#39;: uninitialized constant A (NameError)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s not quite clear what&amp;#39;s happening here since the message isn&amp;#39;t very clear about the real
problem and it gets even more complicated to understand in a real complex code base. Requiring
&amp;#39;a/b&amp;#39; before requiring &amp;#39;a&amp;#39; will cause a circular dependency issue. When &amp;quot;module A&amp;quot; is seen
inside &amp;quot;a/b.rb&amp;quot;, it doesn&amp;#39;t exist yet and the &amp;quot;autoload :A, &amp;#39;a&amp;#39;&amp;quot; tells Ruby it should require &amp;#39;a&amp;#39;
in that case. So, this is what it does, but &amp;#39;a.rb&amp;#39; will require &amp;#39;a/b.rb&amp;#39; which we were trying to
load in the first place. There are other similar problems that are caused by autoload and that&amp;#39;s
why I don&amp;#39;t use it myself despite the potential of loading the application faster. Ideally Ruby
should provide support for some sort of pre-compiled (or pre-parsed) files which would be useful
for big applications to speed up code loading since the disk I/O is not the bottleneck but the
Ruby parsing itself.&lt;/p&gt;
&lt;h3&gt;ActiveSupport::Dependencies Caveats&lt;/h3&gt;
&lt;p&gt;ActiveSupport::Dependencies is a pretty decent reloader and I guess most people are just fine
with it and its known caveats. However there are some people, like me, which are more picky.&lt;/p&gt;
&lt;p&gt;Before I get into the picky parts, let&amp;#39;s explore the limitations one has to have in mind when
using a reloader that relies on running some file code multiple times. The only really safe
strategy I can think of for handling auto-reloading is to completely restart the application
or to use the fork/exec approach. They have their own caveat, like being slower than the
alternatives, so it&amp;#39;s always about trade-offs when it comes to auto-reloaders. Running some
code more than once can lead to unexpected results since not all actions can be rolled back.&lt;/p&gt;
&lt;p&gt;For example, if you include some module to ::Object, this can&amp;#39;t be undone. And even if we could
work around it, we&amp;#39;d have to detect such automatically which would perform so badly that it
would be probably better to simply restart everything. This applies to monkey patching, to
creating some constants in namespaces which are not reloadable (like defining
JSON::CustomExtension) and similar situations. So, when we are dealing with automatic
reloaders we should keep that in mind and understand that reloading will never be perfect
unless we actually restart the full application (or use fork/exec). ActiveSupport::Dependencies
provides some options as autoload_once_paths so that such code wouldn&amp;#39;t be executed more than
once but if you have to change such code then you&amp;#39;ll be forced to restart the full application.&lt;/p&gt;
&lt;p&gt;Also, any file actually required rather than loaded (either with require or require_relative)
won&amp;#39;t be auto-reloaded, which forces the author to always use require_dependency to load
files that are supposed to be reloadable.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s what I dislike about it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ActiveSupport::Dependencies is part of ActiveSupport and relies on some monkey patches to
core classes. I try to avoid monkey patching core classes at all costs so I don&amp;#39;t like AS
in general due to its monkey patching approach;&lt;/li&gt;
&lt;li&gt;Autoloading is not opt-in as far as I know, so I can opt out and I&amp;#39;d rather prefer to not
using it;&lt;/li&gt;
&lt;li&gt;Since some Ruby sources will make use of &amp;quot;require_dependency&amp;quot; and since some Rails related
gems may rely on the automatic autoloading feature provided by ActiveSupport::Dependencies it
forces applications to override &amp;quot;require&amp;quot; and use ActiveSupport::Dependencies even in production
mode;&lt;/li&gt;
&lt;li&gt;If your application doesn&amp;#39;t rely on ActiveSupport then this reloader will add some overhead
to the download phase of Bundler.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Among the options covered in this article, ActiveSupport::Dependencies is my favorite one
although I would consider rerun or shotgun when running on MRI and Linux if the application
starts quickly and I wouldn&amp;#39;t have to work on performance improvements (in that case, it&amp;#39;s
useful to have the behavior of performing like in production when no files have been changed).&lt;/p&gt;
&lt;p&gt;Basically, if your application is fast to load then it may make sense to start with rerun or
shotgun since they are the only real safe bets I can think of.&lt;/p&gt;
&lt;p&gt;However, I performed a few metrics in my application and decided it worth creating a new
transparent reloader that would also fix some of the caveats I see in ActiveSupport::Dependencies.
I &lt;a href=&quot;2016_07_18_autoreloader_a_transparent_automatic_code_reloader_for_ruby&quot;&gt;wrote a new article about&lt;/a&gt;
&lt;a href=&quot;https://github.com/rosenfeld/auto_reloader&quot;&gt;auto_reloader&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you know about other automatic code reloaders for Ruby I&amp;#39;d love to know about them. Please
let me know in the comments section. Also let me know if you think I misunderstood how any of
those mentioned in this article actually works.&lt;/p&gt;
</content:encoded></item><item><title>The sad state of streaming in Ruby web applications</title><link>https://rosenfeld.page/articles/ruby-rails/2016_07_02_the_sad_state_of_streaming_in_ruby_web_applications/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2016_07_02_the_sad_state_of_streaming_in_ruby_web_applications/</guid><pubDate>Sat, 02 Jul 2016 11:57:00 GMT</pubDate><content:encoded>&lt;p&gt;This article is basically a copy of &lt;a href=&quot;https://github.com/rosenfeld/devise-and-streaming&quot;&gt;this project&amp;#39;s README&lt;/a&gt;.
You may read it there if you prefer. It&amp;#39;s a sample application demonstrating
the current streaming state with Devise or Warden.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/plataformatec/devise&quot;&gt;Devise&lt;/a&gt; is an authentication library built
on top of &lt;a href=&quot;https://github.com/hassox/warden&quot;&gt;Warden&lt;/a&gt;, providing a seamless integration
with Rails apps. This application was created following the steps described in Devise&amp;#39;s
Getting Started section. Take a look at the individual commits and their messages if
you want to check each step.&lt;/p&gt;
&lt;p&gt;Warden is a &lt;a href=&quot;http://rack.github.io/&quot;&gt;Rack&lt;/a&gt;&amp;#39;s middleware and authentication is handled
using a &amp;quot;throw/catch(:warden)&amp;quot; approach. This works fine with Rails
&lt;a href=&quot;https://github.com/plataformatec/devise/issues/2332&quot;&gt;until streaming is enabled with ActionController::Live&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;José Valim &lt;a href=&quot;https://github.com/plataformatec/devise/issues/2332#issuecomment-14977804&quot;&gt;pointed out&lt;/a&gt;
that the problem is ActionController::Live&amp;#39;s fault. This is because the Live module
changes the &amp;quot;process&amp;quot; method so that it runs inside a spawn thread, so that it can
return to finish processing the remaining middlewares in the stack. Nothing is sent
to the connection before leaving that method due to the Rack issue I&amp;#39;ll describe
next. But the &amp;quot;process&amp;quot; method will also handle all filters (before/around/after
action hooks). Usually the authentication happens in a before action filter and if
the user is not authentication Devise will &amp;quot;throw :warden&amp;quot; but since this is
running in a spawn thread, the Warden middleware doesn&amp;#39;t have the chance to catch
this symbol and handle it properly.&lt;/p&gt;
&lt;h2&gt;The Rack issue&lt;/h2&gt;
&lt;p&gt;I find it amusing that after so many years of web development with Ruby, Rack
doesn&amp;#39;t seem to have evolved much to better handling streamed responses, including
SSE and why not websockets. The basic blocks are basically the same as when Rack
was first created in a successful attempt to add a standard API web servers and
frameworks could agree and build on top of it. This is a great achievement but
Rack should evolve to better handle streamed responses.&lt;/p&gt;
&lt;p&gt;Aaron Patterson has tried to work on &lt;a href=&quot;https://github.com/tenderlove/the_metal&quot;&gt;another API&lt;/a&gt;
for Rack that would improve support for streaming but it seems it would break middlewares,
and currently it seems &lt;a href=&quot;http://rebuild.fm/122/&quot;&gt;the metal is dead&lt;/a&gt;. Sounds like
HTTP 2.0 multiplexing requires yet more changes, so maybe we&amp;#39;ll get proper support
in Rack 3.0, which should be backward compatible and keep supporting existing middlewares,
by providing alternative APIs, but that seems like it could take years to get there.
&lt;a href=&quot;https://tenderlovemaking.com/2011/03/03/rack-api-is-awkward.html&quot;&gt;He has also written about the issues with Rack API over 5 years ago&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Currently, the way Rack applications handle streaming is by implementing an object
that responds to each that will yield a chunk at a time until the stream is finished,
which is usually implemented by providing the user an API similar to a proper stream
object as properly implemented in other languages. A few years ago an alternative
system has been suggested, which became known as the
&lt;a href=&quot;http://www.rubydoc.info/github/rack/rack/file/SPEC#Hijacking&quot;&gt;hijacking API&lt;/a&gt;. The
&lt;a href=&quot;http://old.blog.phusion.nl/2013/01/23/the-new-rack-socket-hijacking-api/&quot;&gt;Phusion team covered it when it was introduced&lt;/a&gt;
but I think the &amp;quot;partial hijacking&amp;quot; section is no longer valid.&lt;/p&gt;
&lt;p&gt;Rack was designed on top of a middleware stack which means any response will only
start after all middlewares have been called and returned (except if hijacking is used),
since middlewares don&amp;#39;t have access to the socket stream. That&amp;#39;s why Rails had to resort
to using threads to handle streamed/chunked responses. But it can offer other alternative
implementations that would be more friendly to how Warden and Devise work as
demonstrated in this application, which I&amp;#39;ll discuss in the next section.&lt;/p&gt;
&lt;p&gt;Before talking about Rails current options, I&amp;#39;d like to stress a bit more the
problem with Rack without hijacking, and consequently how it affects web development
in Ruby in a negative way, when compared to how this is done in most other languages.&lt;/p&gt;
&lt;p&gt;If we compare to how streaming is handled in Grails (and most JVM based frameworks)
, or most of the main web frameworks in other languages, it couldn&amp;#39;t be any simpler.
Each request thread (or process) has access to a &amp;quot;response&amp;quot; object that accepts
a &amp;quot;write&amp;quot; call that goes directly to the socket&amp;#39;s output (or after a &amp;quot;flush&amp;quot; call).&lt;/p&gt;
&lt;p&gt;There&amp;#39;s no need to flag a controller as capable of streaming. They are just regular
controllers. The request thread or process does not have to spawn another thread
to handle streaming, so there&amp;#39;s nothing special with such controllers.&lt;/p&gt;
&lt;p&gt;It would be awesome if Ruby web applications had the option to use a more flexible
API, more friendly to streamed responses, including SSE and websockets. Hijacking
currently seems to be considered a second-class citizen since they are usually
ignored by major web frameworks like Rails itself.&lt;/p&gt;
&lt;h2&gt;The Rails case (or how to work around the current state in Rack apps)&lt;/h2&gt;
&lt;p&gt;So, with Rails one doesn&amp;#39;t flag an action as one requiring streaming support. They
have to flag the full controller. In theory all other actions not taking advantage
of the streaming API should work just like regular controllers not flagged with
ActionController::Live.&lt;/p&gt;
&lt;p&gt;The obvious question is then, &amp;quot;so, why isn&amp;#39;t Live always included?&amp;quot;. After all,
the Rails users wouldn&amp;#39;t have to worry about enabling streaming, it would be simply
enabled by default for when you want it. One might think that it would be related
to performance concerns but I suspect that the main problem is that this is not
issues free.&lt;/p&gt;
&lt;p&gt;Some middleware assume that the inner middlewares have finished
(some of them actually depend on them to be finished) so that they can modify the
original response or headers. This kind of post-processing middlewares do not work
well with streamed responses.&lt;/p&gt;
&lt;p&gt;This includes caching middlewares (handling ETag or
last-modified headers), monitoring middlewares injecting some HTML (like NewRelic
does automatically by default for example) and many other. Those middlewares will
block the stack until the response is fully finished which breaks the desired
streamed output. Some of them will check some conditions and skip this blocking
behavior under certain circumstances but some will still cause some hard to debug
issues or they may be even conceptually broken.&lt;/p&gt;
&lt;p&gt;There are also some middlewares that expect the controller&amp;#39;s action code to run
in the same thread due to the implementation details surrounding them. For example,
if a sandboxed database environment is implemented as a middleware that runs the
following layer inside a transaction block that will be rolled back, and if the
connection is automatically fetched using the current thread id as the access key,
then spawning a new thread would run in a different connection and out of the
middleware&amp;#39;s transaction, breaking the sandboxed environment. I think ActiveRecord
fetches the connection from thread locals and since ActionController::Live will
copy those locals to the new spawned thread it probably works, but I&amp;#39;m just
warning that spawning threads may break several middlewares in unexpected ways.&lt;/p&gt;
&lt;p&gt;This includes the behavior of Warden communication. So, enabling Live in all
Rails controllers would have the immediate effect of breaking most current
Rails applications as Devise is the de facto authentication standard for Rails
apps. Warden assumes the code handling authentication checks is running in the
same thread. It could certainly offer another strategy to inform about failed
authentication, but this is not how it currently works.&lt;/p&gt;
&lt;p&gt;Even though José Valim said there&amp;#39;s nothing they could do because it&amp;#39;s Live&amp;#39;s
fault, this is not completely true. I guess he meant that it would be too much
work to make it work. After all, we can&amp;#39;t simply put the fault on Live since
the fault actually lies in Rack itself, so streaming is fundamentally broken.&lt;/p&gt;
&lt;p&gt;Devise could certainly subclass Warden::Manager and use this subclass as its
middleware and overwrite &amp;quot;call&amp;quot; to add some object to env, for example, that
would listen to reported failures and they could replace &amp;quot;throw :warden&amp;quot; in
its own code with a more higher level API that would communicate to warden
properly. But I agree this is a mess and probably doesn&amp;#39;t worth, specially
because it couldn&amp;#39;t be called exactly Warden compatible. Another option could
be to change Warden itself so that it doesn&amp;#39;t expect the authentication checks
to happen in the same thread. Or it could replace the &amp;quot;throw-catch&amp;quot; approach
with a &amp;quot;raise/rescue&amp;quot; one, which should work out of the box to how Rails
currently handles it. It shouldn&amp;#39;t be hard for Devise itself to wrap Warden
and use Exceptions rather than throw-catch, but again, I&amp;#39;m not sure if this
is really worthy.&lt;/p&gt;
&lt;p&gt;So, let&amp;#39;s explore other options, which adds other API options to Rails itself.&lt;/p&gt;
&lt;h3&gt;A suggestion to add a new API to Rails&lt;/h3&gt;
&lt;p&gt;The Warden case is a big issue since Devise is very popular among Rails apps
and shouldn&amp;#39;t be ignored. Usually the authentication is performed in filters
rather than in the action itself. Introducing a new API would give the user
the chance of performing authentication in the main request thread before
spawning the streamed thread. This works even if the authentication check is
done directly in the action rather than in the filters. The API would work
something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;def my_action
  # optionally call authenticate_user! here, if not using filters
  streamed do |stream|
    3.times{stream.write &amp;quot;chunk&amp;quot;; sleep 1}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, the thread would only be spawned after the authentication check is
finished. Or &amp;quot;streamed&amp;quot; could use &amp;quot;env[&amp;#39;rack.hijack&amp;#39;]&amp;quot; when available instead
of spawning a new thread.&lt;/p&gt;
&lt;h3&gt;Use Rack hijacking&lt;/h3&gt;
&lt;p&gt;Another alternative might be to support streaming only for web servers supporting
Rack hijacking. This way, the stream API could work seamless, without requiring
&amp;quot;ActionController::Live&amp;quot; to be included. When &amp;quot;response.stream&amp;quot; is used, it would
use &amp;quot;env[&amp;#39;rack.hijack_io&amp;#39;]&amp;quot; if available or either buffer the responses and send
them at once or raise some error, based on some configuration accordingly to the
user&amp;#39;s preferences, as sometimes streaming is not only an optimization but a
requirement that shouldn&amp;#39;t be silently ignored. The same behavior would apply when
HTTP 1.0 is used for example.&lt;/p&gt;
&lt;p&gt;Or another module such as &amp;quot;ActionController::LiveHijacking&amp;quot; could be created so
that Rails users would have that option for a while until Rails thinks this
approach is stable enough to be enabled by default.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I&amp;#39;d like to propose two discussions around this issue. One would be a better
solution for Rack applications to get to talk directly to the response (
or discussing an strategy for making Rack hijacking a first-class citizen
and probably call it something better than hijack). And
the other solution would be for Rails to improve support for streaming
applications by better handling cases like the Warden/Devise issue. I&amp;#39;ve
copied this text with some minor changes to my site so that it could be
discussed in the Disqus&amp;#39; comments section or we could discuss it in the
issues section of this sample project or in the rails-core mailing list,
your call.&lt;/p&gt;
</content:encoded></item><item><title>A sample Ruby script to achieve fast incremental back-up on btrfs partition</title><link>https://rosenfeld.page/articles/infrastructure/2016_06_24_a_sample_ruby_script_to_achieve_fast_incremental_back_up_on_btrfs_partition/</link><guid isPermaLink="true">https://rosenfeld.page/articles/infrastructure/2016_06_24_a_sample_ruby_script_to_achieve_fast_incremental_back_up_on_btrfs_partition/</guid><pubDate>Fri, 24 Jun 2016 15:31:00 GMT</pubDate><content:encoded>&lt;p&gt;For some years I have been using &lt;a href=&quot;http://rsnapshot.org/&quot;&gt;rsnapshot&lt;/a&gt; to back up our databases
and documents using an incremental approach. We create a new back-up every hour and retain the
last 24 hours backup, one back-up per day for the past 7 days and one back-up per week for the
past 4 weeks.&lt;/p&gt;
&lt;p&gt;Rsnapshot is great. It uses hard-links to achieve incremental back-up, saving up a lot of space.
It&amp;#39;s a combination of &amp;quot;cp -al&amp;quot; and rsync.  But we were facing a problem related to free inodes
count on our ext4 partition. By the way, NewRelic does not monitor the free inodes count (df -i)
so I found this problem the hard way, after the back-up stopped working due to lack of free inodes.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve created a custom check in our own monitoring system to alert about low free inodes available
and then I tried to tweak some ext4 settings to avoid this problem again in the new partition.
We have 26GB spread on 2.6 million of individually gzipped documents (they are served directly by
nginx) which will create almost 100 million hard-links in that back-up partition. There are
hardlinks around the original documents as well as part of a smart strategy to save space when the
same document is used in multiple transactions (they are not changed). Otherwise they would take
some extra Gigabytes.&lt;/p&gt;
&lt;p&gt;Recently, my custom monitoring system sent me an alert that 75% of the inodes were used while
about only 30% of disk space was being actually used. So, I decided to investigate a bit more
about other filesystems which dealt with inodes dynamically.&lt;/p&gt;
&lt;h2&gt;The btrfs filesystem&lt;/h2&gt;
&lt;p&gt;That&amp;#39;s how I found btrfs, a modern file-system which not only does not have a limit on inodes but,
as I&amp;#39;ll describe, has some very interesting features for dealing with incremental back-up in a
faster and better way than rsnapshot.&lt;/p&gt;
&lt;p&gt;Initially I wasn&amp;#39;t thinking about replacing rsnapshot, but after reading about support for
subvolumes and snapshots in btrfs I changed my mind and decided to replace rsnapshot with a custom
script. I&amp;#39;ve tried to adapt rsnapshot for several hours to make the workflow I wanted work
without success though. Here&amp;#39;s &lt;a href=&quot;https://github.com/rsnapshot/rsnapshot/issues/20&quot;&gt;an issue&lt;/a&gt;
related to btrfs support.&lt;/p&gt;
&lt;p&gt;Before I talk about how btrfs helps our back-up system, let me explain a few issues I had with
rsnapshot.&lt;/p&gt;
&lt;h2&gt;Rsnapshot issues&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been living with some issues with rsnapshot in the past years. I want the full back-up
procedure to take less than an hour so that we would be able to run it every hour. I had to
tweak its settings a few times in order to get the script to finish in less than an hour but
in the past days it was taking already almost 40 minutes to complete. A while back, before the
tweaks, I had to change the interval to back-up every two hours.&lt;/p&gt;
&lt;p&gt;One of the slow parts of rsnapshot is removing the last back-up snapshot when rotating. It doesn&amp;#39;t
matter if you use &amp;quot;rm -rf&amp;quot; or whatever other method. &lt;a href=&quot;http://blog.liw.fi/posts/rm-is-too-slow/&quot;&gt;Removing a big tree of files is slow&lt;/a&gt;. An alternative would be to move the latest snapshot to the
first one (hourly.0), since this would save the &amp;quot;rm -rf&amp;quot; time and also the &amp;quot;cp -al&amp;quot; time, skipping
to the rsync phase. But I wasn&amp;#39;t able to figure out how to make that happens with rsnapshot.&lt;/p&gt;
&lt;p&gt;Also, some of the procedures could be done in parallel to speed up the process but rsnapshot
doesn&amp;#39;t provide direct support to specify this and it&amp;#39;s hard to write proper shell script to
manage those cases.&lt;/p&gt;
&lt;h2&gt;The goal&lt;/h2&gt;
&lt;p&gt;After reading about btrfs I figured out that the back-up procedure could be made much faster and
be simplified. Then I created a Ruby script, which I&amp;#39;ll show in the next section, and integrated
it in our automation tools in one day. I&amp;#39;ve replaced rsnapshot with it in our back-up server,
with the new script and it&amp;#39;s running pretty well for the last two days taking about 8 minutes to
complete the procedure on each run.&lt;/p&gt;
&lt;p&gt;So, let me explain the strategy I wanted to implement to help you understanding the script.&lt;/p&gt;
&lt;p&gt;As I said, btrfs supports subvolumes. Btrfs implements copy-on-write (CoW), so basically, 
this allows to both create and delete snapshots from subvolumes instantly (constant time). That
means we replace the slow &amp;quot;rm -rf hourly.23&amp;quot; with the instantaneous
&amp;quot;btrfs subvolume delete hourly.23&amp;quot; and &amp;quot;cp -al ...&amp;quot; with the instantaneous
&amp;quot;btrfs subvolume snapshot ...&amp;quot;.&lt;/p&gt;
&lt;p&gt;In order for a regular user to delete subvolumes with btrfs, the user_subvol_rm_allowed fs option
must be used. Also, deleting a subvolume doesn&amp;#39;t work if there are other subvolumes inside it, so
they must be removed first. There&amp;#39;s no switch or tool in the btrfs-progs package that allows you
to delete them recursively. This is important to understand the script.&lt;/p&gt;
&lt;p&gt;Our back-up procedure consists of getting a recent dump of two production PostgreSQL databases
(the main database and the one used by Redmine) and syncing two directories containing files
(the main application files and the files uploaded to Redmine).&lt;/p&gt;
&lt;p&gt;The idea is to get them inside a static path as the first step. The main reason for that is that
if something goes wrong in the process after syncing the documents (the slowest part), for example,
we wouldn&amp;#39;t lose the transferred files the next time we try to run the script. So, basically
here&amp;#39;s how I implemented it (there&amp;#39;s a simpler strategy I&amp;#39;ll explain next):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/var/backups/latest [regular directory]&lt;/li&gt;
&lt;li&gt;/var/backups/latest/postgres [subvolume] - the main db dump is stored here&lt;/li&gt;
&lt;li&gt;/var/backups/latest/tickets-db [subvolume] - the tickets db dump is stored here&lt;/li&gt;
&lt;li&gt;/var/backups/latest/docmanager [subvolume] - the 2.6 million documents are rsynced here&lt;/li&gt;
&lt;li&gt;/var/backups/latest/tickets-files [subvolume] - Redmine files go here&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After the procedure is finished to get them in the latest state it creates a tmp directory and
create a snapshot for each subvolume inside tmp and once everything works fine the back-ups are
rotated and tmp is moved to hourly.0. Removing hourly.23 in the rotation phase has to remove the
inner subvolumes first.&lt;/p&gt;
&lt;p&gt;After implementing this (it was an iterative process) I realized it could be simplified to use
a simpler infra-structure. &amp;quot;latest&amp;quot; would be a subvolume and everything inside it regular files
and directories. Than the &amp;quot;tmp&amp;quot; directory wouldn&amp;#39;t be used and after rotating a snapshot of
&amp;quot;latest&amp;quot; would be used to create &amp;quot;hourly.0&amp;quot;. I didn&amp;#39;t update the script yet because I&amp;#39;m not sure
if it worths changing, since the current layout is more modular, which is useful in case I want
to take some snapshot of just part of the back-up for some reason. So the sample back-up script
in the next section will use my current tested approach, which is the situation described first
above.&lt;/p&gt;
&lt;p&gt;The main database has over 500MB in PostgreSQL custom format, and it&amp;#39;s much faster to rsync it
than using scp. Initially those databases were not stored in the &amp;quot;latest&amp;quot; diretory and I used
&amp;quot;scp&amp;quot; to copy them directly to the &amp;quot;tmp&amp;quot; directory, but I changed the strategy to save some time
and bandwidth.&lt;/p&gt;
&lt;p&gt;The script should exit with a message and non zero exit status code when something fails so that
I would be notified if anything goes wrong by Cron (by setting the MAILTO=&lt;a href=&quot;mailto:my@email.com&quot;&gt;my@email.com&lt;/a&gt; in the
beggining of the crontab file). It shouldn&amp;#39;t affect the existing valid snapshots either in that
case.&lt;/p&gt;
&lt;p&gt;It shouldn&amp;#39;t run in case the previous procedure hasn&amp;#39;t finish, so there&amp;#39;s a simple lock mechanism
preventing that from happen in case it takes over an hour to complete. The second attempt will
fail and I should get an e-mail telling me that happened.&lt;/p&gt;
&lt;p&gt;It should also have a dry-run mode (which I call test mode) that will output the commands without
running it, which is useful while designing the back-up steps. It should also allow for commands
to run concurrently so it uses some indentation to show the order the commands are run.&lt;/p&gt;
&lt;p&gt;Finally, it will report in the logs the issued commands and their status (finished or failed) as
well as any commands output (STDOUT or STDERR) and the time each command took as well as the total
time in the end of the procedure.&lt;/p&gt;
&lt;p&gt;Finally, now that you understand what the script is supposed to do, here&amp;#39;s the actual
implementation.&lt;/p&gt;
&lt;h2&gt;The script&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;#!/usr/bin/env ruby

require &amp;#39;open3&amp;#39;
require &amp;#39;thread&amp;#39;
require &amp;#39;logger&amp;#39;
require &amp;#39;time&amp;#39;

class Backup
  def run(args)
    @start_time = Time.now
    @backup_root_path = File.expand_path &amp;#39;/var/backups&amp;#39;
    #@backup_root_path = File.expand_path &amp;#39;~/backups&amp;#39;
    @log_path = &amp;quot;#{@backup_root_path}/backup.log&amp;quot;
    @tmp_path = &amp;quot;#{@backup_root_path}/tmp&amp;quot;

    @exiting = false
    Thread.current[:indenting_level] = 0

    setup_logger

    lock_or_exit

    log &amp;#39;Starting back-up procedure&amp;#39;

    parse_args args.clone

    run_scripts if @action == &amp;#39;hourly&amp;#39;

    rotate
    unlock
    report_completed
  end

  private

  def setup_logger
    File.write @log_path, &amp;#39;&amp;#39; unless File.exist? @log_path
    logfile = File.open(@log_path, File::WRONLY | File::APPEND)
    logfile.sync = true
    @logger = Logger.new logfile
    @logger.level = Logger::INFO
    @logger.datetime_format = &amp;#39;%Y-%m-%d %H:%M:%S&amp;#39;
    @logger_mutex = Mutex.new
  end

  def lock_or_exit
    if File.exist?(pidfile) &amp;amp;&amp;amp; run_command(&amp;quot;kill -0 #{pid = File.read pidfile}&amp;quot;)
      abort &amp;quot;There&amp;#39;s another backup in progress. Pid: #{pid} (from #{pidfile}).&amp;quot;
    end
    File.write pidfile, Process.pid
  end

  def unlock
    File.unlink pidfile
  end

  def pidfile
    @pidfile ||= &amp;quot;#{@backup_root_path}/backup.pid&amp;quot;
  end

  def run_command!(cmd, sucess_in_test_mode = true, abort_on_stderr: false)
    run_command cmd, sucess_in_test_mode, abort_on_stderr: abort_on_stderr, abort_on_error: true
  end

  def run_command(cmd, sucess_in_test_mode = true, abort_on_stderr: false, abort_on_error: false)
    indented_cmd = &amp;#39; &amp;#39; * indenting_level + cmd
    Thread.current[:indenting_level] += 1
    if @test_mode
      @logger_mutex.synchronize{ puts indented_cmd}
      return sucess_in_test_mode
    end
    start = Time.now
    log &amp;quot;started:  &amp;#39;#{indented_cmd}&amp;#39;&amp;quot;
    stdout, stderr, status = Open3.capture3 cmd
    stdout = stdout.chomp
    stderr = stderr.chomp
    success = status == 0
    log stdout unless stdout.empty?
    log stderr, :warn unless stderr.empty?
    if (!success &amp;amp;&amp;amp; abort_on_error) || (abort_on_stderr &amp;amp;&amp;amp; !stderr.empty?)
      die &amp;quot;&amp;#39;#{cmd}&amp;#39; failed to run with exit status #{status}, aborting.&amp;quot;
    end
    log &amp;quot;finished: &amp;#39;#{indented_cmd}&amp;#39; (#{success ? &amp;#39;successful&amp;#39; : &amp;quot;failed with #{status}&amp;quot;}) &amp;quot; +
      &amp;quot;[#{human_duration Time.now - start}]&amp;quot;
    success
  end

  def indenting_level
    Thread.current[:indenting_level]
  end

  def log(msg, level = :info)
    return if @test_mode
    @logger_mutex.synchronize{ @logger.send level, msg }
  end

  VALID_OPTIONS = [&amp;#39;hourly&amp;#39;, &amp;#39;daily&amp;#39;, &amp;#39;weekly&amp;#39;].freeze
  def parse_args(args)
    args.shift if @test_mode = (args.first == &amp;#39;test&amp;#39;)
    unless args.size == 1 &amp;amp;&amp;amp; VALID_OPTIONS.include?(@action = args.first)
      abort &amp;quot;Usage: &amp;#39;backup [test] action&amp;#39;, where action can be hourly, daily or weekly.
            If test is specified the commands won&amp;#39;t run but will be shown.&amp;quot;
    end
  end

  def die(message)
    log message, :fatal
    was_exiting = @exiting
    @exiting = true
    delete_tmp_path_if_exists unless was_exiting
    unlock
    abort message
  end

  def create_tmp_path
    delete_tmp_path_if_exists
    create_subvolume @tmp_path
  end

  def create_subvolume(path, skip_if_exists = false)
    return if skip_if_exists &amp;amp;&amp;amp; File.exist?(path)
    run_script %Q{btrfs subvolume create &amp;quot;#{path}&amp;quot;}
  end

  def delete_tmp_path_if_exists
    delete_subvolume_if_exists @tmp_path, delete_children: true
  end

  def delete_subvolume_if_exists(path, delete_children: false)
    return unless File.exist?(path)
    Dir[&amp;quot;#{path}/*&amp;quot;].each{|s| delete_subvolume_if_exists s } if delete_children
    run_script %Q{btrfs subvolume delete -c &amp;quot;#{path}&amp;quot;}
  end

  def run_script(script)
    run_command! script
  end

  def run_scripts(scripts = all_scripts)
    case scripts
    when Par
      il = indenting_level
      last_il = il
      scripts.map do |s|
        Thread.start do
          Thread.current[:indenting_level] = il
          run_scripts s
          last_il = [Thread.current[:indenting_level], last_il].max
        end
      end.each &amp;amp;:join
      Thread.current[:indenting_level] = last_il
    when Array
      scripts.each{|s| run_scripts s }
    when String
      run_script scripts
    when Proc
      scripts[]
    else
      die &amp;quot;Invalid script (#{scripts.class}): #{scripts}&amp;quot;
    end
  end

  Par = Class.new Array
  def all_scripts
    [
      Par[-&amp;gt;{create_tmp_path}, &amp;quot;mkdir -p #{@backup_root_path}/latest&amp;quot;, dump_main_db_on_d1,
          dump_tickets_db_on_d1],
      Par[local_docs_sync, local_tickets_files_sync, local_main_db_sync, local_tickets_db_sync],
      Par[main_docs_script, tickets_files_script, main_db_script, tickets_db_script],
    ]
  end

  def dump_main_db_on_d1
    %q{ssh backup@backup-server.com &amp;quot;pg_dump -Fc -f /tmp/main_db.dump } +
      %q{main_db_production&amp;quot;}
  end

  def dump_tickets_db_on_d1
    %q{ssh backup@backup-server.com &amp;quot;pg_dump -Fc -f /tmp/tickets.dump redmine_production&amp;quot;}
  end

  def local_docs_sync
    [
      -&amp;gt;{ create_subvolume local_docmanager, true },
      &amp;quot;rsync -azHq --delete-excluded --delete --exclude doc --inplace &amp;quot; +
        &amp;quot;backup@backup-server.com:/var/main-documents/production/docmanager/ &amp;quot; +
        &amp;quot;#{local_docmanager}/&amp;quot;,
    ]
  end

  def local_docmanager
    @local_docmanager ||= &amp;quot;#{@backup_root_path}/latest/docmanager&amp;quot;
  end

  def local_tickets_files_sync
    [
      -&amp;gt;{ create_subvolume local_tickets_files, true },
      &amp;quot;rsync -azq --delete --inplace backup@backup-server.com:/var/redmine/files/ &amp;quot; +
        &amp;quot;#{local_tickets_files}/&amp;quot;,
    ]
  end

  def local_tickets_files
    @local_tickets_files ||= &amp;quot;#{@backup_root_path}/latest/tickets-files&amp;quot;
  end

  def local_main_db_sync
    [
      -&amp;gt;{ create_subvolume local_main_db, true },
      &amp;quot;rsync -azq --inplace backup@backup-server.com:/tmp/main_db.dump &amp;quot; +
        &amp;quot;#{local_main_db}/main_db.dump&amp;quot;,
    ]
  end

  def local_main_db
    @local_main_db ||= &amp;quot;#{@backup_root_path}/latest/postgres&amp;quot;
  end

  def local_tickets_db_sync
    [
      -&amp;gt;{ create_subvolume local_tickets_db, true },
      &amp;quot;rsync -azq --inplace backup@backup-server.com:/tmp/tickets.dump &amp;quot; +
        &amp;quot;#{local_tickets_db}/tickets.dump&amp;quot;,
    ]
  end

  def local_tickets_db
    @local_tickets_db ||= &amp;quot;#{@backup_root_path}/latest/tickets-db&amp;quot;
  end

  def main_docs_script
    create_snapshot_cmd local_docmanager, &amp;quot;#{@tmp_path}/docmanager&amp;quot;
  end

  def create_snapshot_cmd(from, to)
    &amp;quot;btrfs subvolume snapshot #{from} #{to}&amp;quot;
  end

  def main_db_script
    create_snapshot_cmd local_main_db, &amp;quot;#{@tmp_path}/postgres&amp;quot;
  end

  def tickets_db_script
    create_snapshot_cmd local_tickets_db, &amp;quot;#{@tmp_path}/tickets-db&amp;quot;
  end

  def tickets_files_script
    create_snapshot_cmd local_tickets_files, &amp;quot;#{@tmp_path}/tickets-files&amp;quot;
  end

  LAST_DIR_PER_TYPE = {
    &amp;#39;hourly&amp;#39; =&amp;gt; 23, &amp;#39;daily&amp;#39; =&amp;gt; 6, &amp;#39;weekly&amp;#39; =&amp;gt; 3
  }.freeze
  def rotate
    last = LAST_DIR_PER_TYPE[@action]
    path = -&amp;gt;(n, action = @action){ &amp;quot;#{@backup_root_path}/#{action}.#{n}&amp;quot; }
    delete_subvolume_if_exists path[last], delete_children: true
    n = last
    while (n -= 1) &amp;gt;= 0
      run_script &amp;quot;mv #{path[n]} #{path[n+1]}&amp;quot; if File.exist?(path[n])
    end
    dest = path[0]
    case @action
    when &amp;#39;hourly&amp;#39;
      run_script &amp;quot;mv #{@tmp_path} #{dest}&amp;quot;
    when &amp;#39;daily&amp;#39;, &amp;#39;weekly&amp;#39;
      die &amp;#39;last hourly back-up does not exist&amp;#39; unless File.exist?(hourly0 = path[0, &amp;#39;hourly&amp;#39;])
      create_tmp_path
      Dir[&amp;quot;#{hourly0}/*&amp;quot;].each do |subvolume|
        run_script create_snapshot_cmd subvolume, &amp;quot;#{@tmp_path}/#{File.basename subvolume}&amp;quot;
      end
      run_script &amp;quot;mv #{@tmp_path} #{dest}&amp;quot;
    end
  end

  def report_completed
    log &amp;quot;Backup finished in #{human_duration Time.now - @start_time}&amp;quot;
  end

  def human_duration(total_time_sec)
    n = total_time_sec.round
    parts = []
    [60, 60, 24].each{|d| n, r = n.divmod d; parts &amp;lt;&amp;lt; r; break if n.zero?}
    parts &amp;lt;&amp;lt; n unless n.zero?
    pairs = parts.reverse.zip(%w(d h m s)[-parts.size..-1])
    pairs.pop if pairs.size &amp;gt; 2 # do not report seconds when irrelevant
    pairs.flatten.join
  end
end

Backup.new.run(ARGV) if File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, this is what I get running the test mode:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ruby backup.rb test hourly
btrfs subvolume create &amp;quot;/home/rodrigo/backups/tmp&amp;quot;
mkdir -p /home/rodrigo/backups/latest
ssh backup@backup-server.com &amp;quot;pg_dump -Fc -f /tmp/main_db.dump main_db_production&amp;quot;
ssh backup@backup-server.com &amp;quot;pg_dump -Fc -f /tmp/tickets.dump redmine_production&amp;quot;
 btrfs subvolume create &amp;quot;/home/rodrigo/backups/latest/docmanager&amp;quot;
 btrfs subvolume create &amp;quot;/home/rodrigo/backups/latest/tickets-files&amp;quot;
 btrfs subvolume create &amp;quot;/home/rodrigo/backups/latest/postgres&amp;quot;
 btrfs subvolume create &amp;quot;/home/rodrigo/backups/latest/tickets-db&amp;quot;
  rsync -azHq --delete-excluded --delete --exclude doc --inplace backup@backup-server.com:/var/main-documents/production/docmanager/ /home/rodrigo/backups/latest/docmanager/
  rsync -azq --delete --inplace backup@backup-server.com:/var/redmine/files/ /home/rodrigo/backups/latest/tickets-files/
  rsync -azq --inplace backup@backup-server.com:/tmp/main_db.dump /home/rodrigo/backups/latest/postgres/main_db.dump
  rsync -azq --inplace backup@backup-server.com:/tmp/tickets.dump /home/rodrigo/backups/latest/tickets-db/tickets.dump
   btrfs subvolume snapshot /home/rodrigo/backups/latest/tickets-db /home/rodrigo/backups/tmp/tickets-db
   btrfs subvolume snapshot /home/rodrigo/backups/latest/tickets-files /home/rodrigo/backups/tmp/tickets-files
   btrfs subvolume snapshot /home/rodrigo/backups/latest/postgres /home/rodrigo/backups/tmp/postgres
   btrfs subvolume snapshot /home/rodrigo/backups/latest/docmanager /home/rodrigo/backups/tmp/docmanager
    mv /home/rodrigo/backups/tmp /home/rodrigo/backups/hourly.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &amp;quot;all_scripts&amp;quot; method is the one you should adapt for your needs.&lt;/p&gt;
&lt;h2&gt;Final notes&lt;/h2&gt;
&lt;p&gt;I hope that script will help you serving as a base for your own back-up script in Ruby in case I
was able to convince you to give this strategy a try. Unless you are already using some robust
back-up solution such as Bacula or other advanced systems, this strategy is very simple to
implement, takes little space and allows for fast incremental backups and might interest you.&lt;/p&gt;
&lt;p&gt;Please let me know if you have any questions in the comments section or if you&amp;#39;d suggest any
improvements over it. Or if you think you&amp;#39;ve found a bug I&amp;#39;d love to hear about it.&lt;/p&gt;
&lt;p&gt;Good luck dealing with your back-ups. :)&lt;/p&gt;
</content:encoded></item><item><title>Akita&apos;s Manga Downloadr Elixir vs Ruby performance revisited</title><link>https://rosenfeld.page/articles/ruby-rails/2016_06_20_akita_s_manga_downloadr_elixir_vs_ruby_performance_revisited/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2016_06_20_akita_s_manga_downloadr_elixir_vs_ruby_performance_revisited/</guid><pubDate>Mon, 20 Jun 2016 11:40:00 GMT</pubDate><content:encoded>&lt;p&gt;Two weeks ago I read &lt;a href=&quot;http://www.akitaonrails.com/2016/06/07/manga-downloadr-improving-the-crystal-ruby-from-bursts-to-pool-stream&quot;&gt;an article from Fabio Akita&lt;/a&gt;
comparing the performance of his Manga Downloadr implementations in Elixir, Crystal and Ruby.&lt;/p&gt;
&lt;p&gt;From a quick glance at its source code it seems the application consisted mostly of downloading
multiple pages and another minor part would take care of parsing the HTML and extracting some
location paths and attributes for the images. At least, this was the part that was being tested
in his benchmark. I found it very odd that the Elixir version would finish in about 15s while
the Ruby version would take 27s to complete. After all, this wasn&amp;#39;t a CPU bound application but
an I/O bound one. I would expect that the same design implemented in any programming language
for this kind of application should take about the same time in whatever chosen language. Of
course the HTML parser or the HTTP client implementations used on each language could make some
difference but the Ruby implementation took almost twice the time taken by the Elixir
implementation. I was pretty much confident it had to be a problem with the design rather than
a difference in the raw performance among the used languages.&lt;/p&gt;
&lt;p&gt;I had to prepare a deploy for the past two weeks which happened last Friday. Then on Friday I
decided to take a few hours to understand what the test mode was really all about and rewrote
the Ruby application with a proper design for this kind of application taking Ruby&amp;#39;s limitations
(specially MRI&amp;#39;s ones) in mind with focus on performance.&lt;/p&gt;
&lt;p&gt;The new implementation can be found &lt;a href=&quot;https://github.com/rosenfeld/manga-downloadr-test-performance-mode&quot;&gt;here on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Feel free to give it a try and let me know if you can think of any changes that could potentially
improve the performance in any significant way. I have a few theories my self, like using a SAX
parser rather than performing the full parsing, among a few other improvements I can think of, but
I&amp;#39;m not really sure whether the changes would be significant given that most of the time is
actually spent on network data transfer using a slow connection (about 10MBbps in
my case), if we compare to the time needed to parse those HTMLs.&lt;/p&gt;
&lt;h2&gt;The numbers&lt;/h2&gt;
&lt;p&gt;So, here are the numbers I get with a 10MBps Internet connection and an AMD Phenom II X6 1090T,
with 6 cores at 3.2GHz each:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elixir: 13.0s (best time, usually ranges from 13.0-16s)&lt;/li&gt;
&lt;li&gt;JRuby: 12.3s (best time, usually ranges from 12.3-16s)&lt;/li&gt;
&lt;li&gt;MRI: 10.9s (best time, usually ranges from 10.9-16s)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As I suspected, they should perform about the same. JRuby needs 1.8s just to boot the JVM (
measured with time jruby --dev -e &amp;#39;&amp;#39;), which means it actually takes about the same as MRI if
we don&amp;#39;t take the boot time into consideration (which is usually the case when the application
is running a long-lived daemon like a web server).&lt;/p&gt;
&lt;p&gt;For JRuby threads are used to handle concurrency while in MRI I was forced to use a pool of forked
processes to handle HTML parsing and write some simplified Inter-Process Communication (IPC)
technique which is suitable for this particular test case but may not apply to others. Writing
concurrent code in Ruby could be easier but for MRI it&amp;#39;s specially hard once you want to use
all cores because I find it much easier to write multi-threaded code than to deal with forked
processes and special IPC that is not as trivial to write as using threads that share the same
memory. You are free to test the performance of other approaches in MRI, like the threaded one,
or always forking rather than using a pool of forked processes, changing the amount of workers
both for the downloader as well as for the forked pool (I use 6 processes in the pool that
parses the HTML since I have 6 cores in my CPU).&lt;/p&gt;
&lt;p&gt;I have always been disappointed by the sad state of real concurrency in MRI due to the GIL. I&amp;#39;d
love to have a switch to disable the GIL completely so that I would able to benchmark the
different approaches (threads vs forks). Unfortunately, this is not possible in MRI or JRuby
because MRI has the GIL and JRuby doesn&amp;#39;t handle forking well. Also, Nokogiri does not perform
the same in MRI and JRuby, which means there are many other variables involved that running an
application using forks in MRI cannot be really compared to run it against JRuby using the
multi-threaded approach because the difference in the design is not the only one happening.&lt;/p&gt;
&lt;p&gt;When I really need to write some CPU bound code that would benefit from running on all cores I
often do it in JRuby since I find it easier to deal with threads rather than spawn processes.
Once I had to create an application similar to Akita&amp;#39;s Manga Downloader in test mode and I
&lt;a href=&quot;/en/articles/ruby-rails/2012-03-04-how-nokogiri-and-jruby-saved-my-week&quot;&gt;wrote about how JRuby saved my week&lt;/a&gt;
exactly due to it enabling real concurrency. I really think MRI team should take real concurrency
needs more seriously or it might become irrelevant in the languages and frameworks war. Ruby
usually gives us options, but we don&amp;#39;t really have an option to deal with concurrent code in MRI
as the core developers believe forking is just fine. Since Ruby usually strives for its simplicity
I find this awkward since it&amp;#39;s usually much easier to write multi-threaded code than dealing
with spawn processes.&lt;/p&gt;
&lt;p&gt;Back to the results of the timing comparison between Elixir and Ruby implementations, of course,
I&amp;#39;m not suggesting that Ruby is faster than Elixir. I&amp;#39;m pretty sure the design of the
Elixir implementation can be improved as well to get a better time. I&amp;#39;m just demonstrating that
for this particular use case of I/O bound applications the raw language performance usually does
not make any difference given a proper design. The design is by far the most important feature
when working on performance improvements of I/O bound applications. Of course it&amp;#39;s also important
for CPU bound applications, but what I mean is that the raw performance is often irrelevant for
I/O bound applications while the design is essential.&lt;/p&gt;
&lt;h1&gt;So, what&amp;#39;s the point?&lt;/h1&gt;
&lt;p&gt;There are many features one can use to sell another language but we should really avoid the trap
of comparing raw performance because it hardly matter for most of the applications web developers
work with, if they are the target audience. I&amp;#39;m pretty sure Elixir has great sell points, just
like Rust, Go, Crystal, Mirah and so on. I&amp;#39;d be more interested in learning about the advantages
of their eco-systems (tools, people, libraries) and how they allow to write good designed software
in a better way. Or how they excel in exceptions handling. Or how easy it is to write concurrent
and distributed software with them. Or how robust and fault tolerant they are. Or how they can
help getting zero down-times during deploy, or how fast the applications would boot (this is one
of the raw performance cases where it can matter). How well documented they are and how amazing
are their communities. How one can easily debug and profile applications in these environments or
how easily they can test something in a REPL, or write automated tests, manage dependencies. How
well autoreloading work in the development mode and so on. There are so many interesting aspects
of a language and its surrounding environment that I find it frustrating every time I see someone
trying to sell a language by comparing the raw performance as it often does not matter in most
cases.&lt;/p&gt;
&lt;p&gt;Look, I&amp;#39;ve worked with fast hard real-time systems (running on Linux with real-time patches such as
Xenomai or RTAI) during my master thesis and I know that raw performance is very important for a
broad set of applications, like Robotics, image processing, gaming, operating systems and
many others. But we have to understand whom we are talking to. If the audience is web development
raw performance simply doesn&amp;#39;t matter that much. This is not the feature that will determine
whether your application will scale to thousands of requests per second. Architecture/design is.&lt;/p&gt;
&lt;p&gt;If you are working with embedded systems or hard real time systems it makes sense to use C or
some other language that does not rely on garbage collectors (as it&amp;#39;s hard to implement a garbage
collector with hard timing constraints). But please forget about raw performance for the cases
where it doesn&amp;#39;t make much difference.&lt;/p&gt;
&lt;p&gt;If you know someone who got a degree in Electrical Engineering, like me, and ask them, you&amp;#39;ll
notice it&amp;#39;s pretty common to perform image processing in Matlab, which is an interpreted language
and environment to prototype algorithm designs. It&amp;#39;s focused on operations involving matrix and
they are pretty fast since they are compiled and optimized. Which allows engineers to quickly
test different designs without having to write each variation in C. Once they are happy with the
design and performance of the algorithm they can go a step further and implement it in C or use
one of the Matlab tools that would try to perform this step automatically.&lt;/p&gt;
&lt;p&gt;Engineers are very pragmatic. They want to use the best tools for their jobs. That means a
scripting language should be preferred over a static one during the design/prototype phase as it
allows faster feedback and iterative loop. Sometimes the performance they get with Matlab is
simply fast enough for their needs. The same happens with Ruby, Python, JS and many other
languages. They could be used for prototypes or they could be enough for the actual application.&lt;/p&gt;
&lt;p&gt;Also, one can start with them and once the raw performance becomes a bottleneck they are free
to convert that part to a more efficient language and use some sort of integration to delegate
the expensive parts to them. If there are many parts of the application that would require such
approach to be taken, then it becomes a burden to maintain it and one might consider moving the
complete application to another language to reduce the complexity.&lt;/p&gt;
&lt;p&gt;However, this is not my experience with web applications in all past years I&amp;#39;ve been working as
a web developer. Rails usually takes about 20ms per request as measured by nginx in production
while DNS, network transfer, JS and other related jobs may take a few seconds which means the
20ms spent in the server is simply irrelevant. It could be 0ms and it wouldn&amp;#39;t make any difference
to the user experience.&lt;/p&gt;
</content:encoded></item><item><title>Getting an SPA to load the fastest possible way (and how Webpack can help you)</title><link>https://rosenfeld.page/articles/2016_02_29_getting_an_spa_to_load_the_fastest_possible_way_and_how_webpack_can_help_you/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2016_02_29_getting_an_spa_to_load_the_fastest_possible_way_and_how_webpack_can_help_you/</guid><pubDate>Mon, 29 Feb 2016 11:08:00 GMT</pubDate><content:encoded>&lt;p&gt;This article assumes you completely understand all performance trade-offs related to each
available technique to load scripts and how to modularize them. I&amp;#39;d highly recommend you to
read another article I wrote just to explain them &lt;a href=&quot;/en/articles/2016-02-29-scripts-loading-trade-offs-a-performance-analysis&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Feel free to skip this section if you are not interested in the background.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been using a single JS and a single CSS for my application for a long time.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve optimized the code a lot, by lazily running some parts and performing all best practices with
regards to how to load the resources, minifying them, gzipped them, caching them and so on and,
still, every week about 10% of the users won&amp;#39;t meet the SLA that says the page should load in
within 5s. Some users would load the page under a second even when the resources were not cached.&lt;/p&gt;
&lt;p&gt;To be honest, it&amp;#39;s not really defined under which conditions a user should be able to load the
application in under 5s, so I use the worst scenario to measure this time. After the page is
fully loaded I send the data from the resources timing API to the back-end so that I can extract
some statistics later, since NewRelic is too limiting for this kind of information. Here&amp;#39;s how
it works in our application. The user logs in another application which will provide a link to
ours, containing an authentication token, which we&amp;#39;ll parse, verify and redirect to the root
address. I use the time provided by the resources timing API, which will include this redirect.&lt;/p&gt;
&lt;p&gt;It should be noticed that any actions in the server-side take about 10-20ms, accordingly to the
nginx logging (for the actions related to page loading - opening a transaction or searching the database might take 1s in the server-side for example, depending on the criteria). This means most
of the time is spent outside the server and are influenced by latency, network bandwidth between
the client and server, CDN, presence of cached resources and so on. Of course, running the JS code
itself already contributes to the total time, but this part was already highly optimized before
switching away from Sprockets. Half of the accesses were able to run all JS loading code in up to
637ms. 90% up to 1.3s. 3% loaded between 2 and 2.2s. That means that for the slowest client all
network operations should complete in about 2.8s, including DNS lookup, redirect and bytes
transfer. I can&amp;#39;t make those browser run faster and I can&amp;#39;t save more than 20ms in the server-side,
so my best option is to reduce the amount of data that should be transferred from the server to the
client, as I don&amp;#39;t have much control over our collocation service provider (Cogent - NY), or the
client Internet provider or our CDN provider (CloudFront).&lt;/p&gt;
&lt;p&gt;But I can choose which libraries to use and which code to include in the initial page loading.
When working with performance improvements the first step is always measuring. I created an
application to provide me the analytics I needed to understand the page loading performance so
that I could confirm that I should be now focusing on the download size. To give you an idea,
the fastest access to our application in the last week was 692ms, from an user accessing from
London. The resources were already in cache in this request, the main document loaded in 244ms
and the JS code ran in 301ms, using IE10. No redirect happened for this request.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s another sample for a fast page load including redirect and non cached resources. Some
user from NY loaded the full application in 1.09s. 304ms were spent on redirect, 34ms to load
the main document 107ms to load the CSS and 129ms to load the JS (JS and CSS are loaded in
parallel). It took 479ms for IE11 to process the scripts in this requests.&lt;/p&gt;
&lt;p&gt;Now, let&amp;#39;s take a look in a request which took 8.8s to load to understand why it took so long.
This request used 6s to load the same JS from the same location (NY) while the redirect took 1.9s.
The CSS took 4.3s to load. And this is not a mobile browser, but IE11, and it&amp;#39;s a fast computer
as the scripts took only 453ms to run. When I take a closer look at the other requests taking over
5s, I can confirm the bad network performance is the main reason for this.&lt;/p&gt;
&lt;p&gt;If I want to make them load under 5s I must reduce the amount of data they are downloading. After
noticing that I realized sprockets was in my way for this last bit of performance improvement. I
had already cut a lot of vendored code which were big and I only used a small part of them, so it
was time I had to cut out part of the application code. Well, actually the plan was to post-pone
its loading to when they were needed, for example, after the user made some action like clicking
some button or link. In other words, I was looking for code splitting and I&amp;#39;d had to implement it
on my own if I were to keep using my current stack (Sprockets by that time, or the Rails Assets
Pipeline) but I decided to switch to another better tool as I also wanted source-maps support
and other features I couldn&amp;#39;t get with Sprockets.&lt;/p&gt;
&lt;p&gt;Source maps are very important to us because we report any JS errors to our servers including
backtraces for future analysis and having the source-maps available makes it much easier to
figure out the exact place an exception happened.&lt;/p&gt;
&lt;h2&gt;Goals&lt;/h2&gt;
&lt;p&gt;In the context of big single page applications, the ideal resources build tool should be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;support code modularization (understands AMD, CommonJS, allows easy shimming and features
to integrate with basically any third-party library without having to modify their sources);&lt;/li&gt;
&lt;li&gt;concatenate sources in bundles, which should be optimized to avoid missing all cache upon
frequent deploys;&lt;/li&gt;
&lt;li&gt;support code splitting (lazy code loading) - Sprockets and many other tools do not support this,
which would require each developer to roll their own solution) to not force the user to download
more code than what is required for the initial page rendering;&lt;/li&gt;
&lt;li&gt;minify JS and CSS for production environments;&lt;/li&gt;
&lt;li&gt;provide a fast watch mode for development mode;&lt;/li&gt;
&lt;li&gt;provide source maps;&lt;/li&gt;
&lt;li&gt;allow CSS to be embedded in JS bundles as well as allowing a separate CSS file (more on that
in the following sections);&lt;/li&gt;
&lt;li&gt;support CSS and JS preprocessors/compilers, like Babel, CoffeeScript, SASS, templating languages
and so on;&lt;/li&gt;
&lt;li&gt;support filenames containing content-based hashes to support permanent caching;&lt;/li&gt;
&lt;li&gt;provide great integration with NPM and bower packages;&lt;/li&gt;
&lt;li&gt;fast build time for the production-ready configuration to speed up deploys though the usage of
persistent caching (on disk, Redis or memcached, for example);&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Webpack was the only solution I was able to find which supported all of the items above except
for the last one. Sprockets and other solutions are able to handle persistent cache to speed up
the final build and consequently the deploy process. Unfortunately the deploy will be a bit slow
with webpack, but at least the application should be highly optimized for performance.&lt;/p&gt;
&lt;p&gt;If you are aware of other tools that allow the same techniques discussed in this article to be
implemented, please let me know in the comments, if possible with examples on how to reproduce
the set-up presented in this article.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;set-up-instructions&quot;&gt;The webpack set-up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This article is already very long, so I don&amp;#39;t intend it to become a webpack tutorial. Webpack has
an extensive documentation about most of what you&amp;#39;ll need and I&amp;#39;ll try to cover here the parts
which are not covered by the documentation and the tricks I had to implement to make it meet the
goals I stated above.&lt;/p&gt;
&lt;p&gt;The first step is to create some webpack.config.js configuration file and to install webpack
(which also means installing npm and node.js). I decided to create a new directory under
app-root/app/resources and perform these commands there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo apt-get install nodejs npm
# I had to create a symlink in /usr/bin too on Ubuntu/Debian to avoid some problems with some
# npm packages. Feel free to install node.js and npm from other means if you prefer
cd /usr/bin &amp;amp;&amp;amp; sudo ln -s nodejs node
mkdir -p app/resources
cd app/resources
# you should use --save when installing packages so that they are added to package.json
# automatically. I also use npm shwrinkwrap to generate a npm-shrinkwrap.json file which
# is similar to Gemfile.lock for the bundler Ruby gem
npm init
npm install webpack --save
npm install bower --save
bower install jquery-ui --save
# there are many other dependencies, please check the package.json sample below for more
# required dependencies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The build resources would be generated in app-root/public/assets and the test files under
app-root/public/assets/specs. It looks for resources in app/resources/src/js,
app/resources/node_modules, app/resources/bower_components,
app/assets/javascripts, app/assets/stylesheets, app/assets/images and a few other paths.&lt;/p&gt;
&lt;p&gt;webpack.config.js:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;
var webpack = require(&amp;#39;webpack&amp;#39;);
var glob = require(&amp;#39;glob&amp;#39;);
var merge = require(&amp;#39;merge&amp;#39;);
var fs = require(&amp;#39;fs&amp;#39;);
var path = require(&amp;#39;path&amp;#39;);
// the AssetsPlugin generates the webpack-assets.json, used by the backend application
// to find the generated files per entry name
var AssetsPlugin = require(&amp;#39;assets-webpack-plugin&amp;#39;);

var PROD = JSON.parse(process.env.PROD || &amp;#39;0&amp;#39;);
var BUILD_DIR = path.resolve(&amp;#39;../../public/assets&amp;#39;);

var mainConfig = {
  context: __dirname + &amp;#39;/src&amp;#39;
  ,output: {
    publicPath: &amp;#39;/assets/&amp;#39;
    , path: BUILD_DIR
    , filename: &amp;#39;[name]-[chunkhash].min.js&amp;#39;
  }
  ,resolveLoader: {
    alias: { &amp;#39;ko-loader&amp;#39;: __dirname + &amp;#39;/loaders/ko-loader&amp;#39; }
    , fallback: __dirname + &amp;#39;/node_modules&amp;#39;
  }
  ,module: {
    loaders: [
      { test: /\.coffee$/, loader: &amp;#39;coffee&amp;#39; }
      , { test: /\.(png|gif|jpg)$/, loader: &amp;#39;file&amp;#39;}
      // it&amp;#39;s possible to specify that some files should be embedded depending on their size
      //, { test: /\.png$/, loader: &amp;#39;url?limit=5000&amp;#39;}
      , { test: /\.eco$/, loader: &amp;#39;eco-loader&amp;#39; }
      , { test: /knockout-latest\.debug\.js$/, loader: &amp;#39;ko-loader&amp;#39; }
      , { test: /jquery-ujs/, loader: &amp;#39;imports?jQuery=jquery&amp;#39;}
    ]
  }
  , devtool: PROD ? &amp;#39;source-map&amp;#39; : &amp;#39;cheap-source-map&amp;#39;
  , plugins: [ new AssetsPlugin() ]
  , cache: true // speed up watch mode (in-memory caching only)
  , noParse: [ &amp;#39;jquery&amp;#39;
    , &amp;#39;jquery-ui&amp;#39;
  ]
  , resolve: {
    root: [
      path.resolve(&amp;#39;./src/js&amp;#39;)
      , path.resolve(&amp;#39;../assets/javascripts&amp;#39;)
      , path.resolve(&amp;#39;../assets/stylesheets&amp;#39;)
      , path.resolve(&amp;#39;../assets/images&amp;#39;)
      , path.resolve(&amp;#39;../../vendor/assets/javascripts&amp;#39;)
      , path.resolve(&amp;#39;../../vendor/assets/stylesheets&amp;#39;)
      , path.resolve(&amp;#39;../../vendor/assets/images&amp;#39;)
      , path.resolve(&amp;#39;./node_modules&amp;#39;)
      , path.resolve(&amp;#39;./bower_components&amp;#39;)
    ]
  , entry: { &amp;#39;app/client&amp;#39;: [&amp;#39;client.js&amp;#39;]
    , &amp;#39;app/internal&amp;#39;: [&amp;#39;internal.js&amp;#39;]
    // other bundles go here... Since internal.js requires client.js and it&amp;#39;s also a bundle
    // entry, webpack will complain unless we put the dependency as an array (internal details)
  }
  , alias: {
    // this is required because we are using jQuery UI from bower for the time being
    // since the latest stable version is not published to npm and also because the new beta,
    // which is published to npm introduces lots of incompatibilities with the previous version
    &amp;#39;jquery.ui.widget$&amp;#39;: &amp;#39;jquery-ui/ui/widget.js&amp;#39;
  }
};

// we save the current loaders for use with our themes bundles, as we&amp;#39;ll add additional
// loaders to the main config for handling CSS and CSS is handled differently for each config
var baseLoaders = mainConfig.module.loaders.slice()

var themesConfig = merge.recursive(true, mainConfig);

// this configuration exists to generate the initial CSS file, which should be minimal, just
// enough to load the &amp;quot;Loading page...&amp;quot; initial layout as well as the theme specific rules
// for the main config we embed the CSS rules in the JS bundle and add the style tags
// dynamically to the DOM because the initial CSS will block the page rendering and we want
// to display the &amp;quot;loading...&amp;quot; information as soon as possible.

themesConfig.entry = { &amp;#39;app/theme-default&amp;#39;: &amp;#39;./css/themes/default.js&amp;#39;
  , &amp;#39;app/theme-uk&amp;#39;: &amp;#39;./css/themes/uk.js&amp;#39;
};

var ExtractTextPlugin = require(&amp;#39;extract-text-webpack-plugin&amp;#39;);
themesConfig.plugins.push(new ExtractTextPlugin(&amp;#39;[name]-[chunkhash].css&amp;#39;));

var cssExtractorLoader = path.resolve(&amp;#39;./loaders/non-cacheable-extract-text-webpack-loader.js&amp;#39;) +
  &amp;#39;?&amp;#39; + JSON.stringify({omit: 1, extract: true, remove: true }) + &amp;#39;!style!css&amp;#39;;

themesConfig.module.loaders.push(
  { test: /\.scss$/,
    // code splitting and source-maps don&amp;#39;t work well together when using relative paths
    // in a background url for example. That&amp;#39;s why source-maps are not enabled for SASS
    loader: cssExtractorLoader + &amp;#39;!sass&amp;#39;
  }
  , { test: /\.css$/, loader: cssExtractorLoader }
);

mainConfig.module.loaders.push(
  { test: /\.scss$/, loaders: [&amp;#39;style&amp;#39;, &amp;#39;css&amp;#39;, &amp;#39;sass&amp;#39;] }
  , { test: /\.css$/, loaders: [&amp;#39;style&amp;#39;, &amp;#39;css&amp;#39;] }
);

module.exports = [ mainConfig, themesConfig ]

if (!PROD) { // process the specs bundles - webpack must be restarted if a new spec file is created
  var specs = glob.sync(&amp;#39;../../spec/javascripts-src/**/*_spec.js*&amp;#39;);
  var entries = {};
  specs.forEach(function(s) {
    var entry = s.replace(/.*javascripts-src\/(.*)\.js.*/, &amp;#39;$1&amp;#39;);
    entries[entry] = path.resolve(s);
  });
  var specsConfig = merge.recursive(true, mainConfig, {
    output: { path: path.resolve(&amp;#39;../../public/assets/specs&amp;#39;)
      , publicPath: &amp;#39;/assets/specs/&amp;#39;
      , filename: &amp;#39;[chunkhash]-[name].min.js&amp;#39;
    }
  });
  specsConfig.entry = entries;
  specsConfig.resolve.root.push(path.resolve(&amp;#39;../../spec/javascripts-src&amp;#39;));
  module.exports.push(specsConfig);
};

mainConfig.entry.vendor = [&amp;#39;jquery&amp;#39;
, &amp;#39;jquery-ujs&amp;#39;
, &amp;#39;knockout&amp;#39;
// those jquery-ui-*.js were created to include the required CSS as well since the jquery-ui
//  integration from the bower package is not perfect
, &amp;#39;jquery-ui-autocomplete.js&amp;#39;
, &amp;#39;jquery-ui-button.js&amp;#39;
, &amp;#39;jquery-ui-datepicker.js&amp;#39;
, &amp;#39;jquery-ui-dialog.js&amp;#39;
, &amp;#39;jquery-ui-resizable.js&amp;#39;
, &amp;#39;jquery-ui-selectmenu.js&amp;#39;
, &amp;#39;jquery-ui-slider.js&amp;#39;
, &amp;#39;jquery-ui-sortable.js&amp;#39;
, &amp;#39;lodash/intersection.js&amp;#39;
, &amp;#39;lodash/isEqual.js&amp;#39;
, &amp;#39;lodash/sortedUniq.js&amp;#39;
, &amp;#39;lodash/find.js&amp;#39;
, &amp;#39;./js/vendors-loaded.js&amp;#39; // the application code won&amp;#39;t run until window.VENDORS_LOADED is true
// which is set by vendors-loaded.js. This was implemented so that those bundles could be
// downloaded asynchronously
];

mainConfig.plugins.push(new webpack.optimize.CommonsChunkPlugin({ name: &amp;#39;vendor&amp;#39;
, filename: &amp;#39;vendor-[chunkhash].min.js&amp;#39;
, minChunks: Infinity
}));

// prepare entries for lazy loading without losing the source-maps feature
// we replace webpackJsonp calls with webpackJsonx and implement the latter in an inline
// script in the document so that it waits for the vendor script to finish loading
// before running the webpackJsonp with the received arguments. Webpack doesn&amp;#39;t support
// async loading of the commons and entry bundles out of the box unfortunately, so this is a hack
mainConfig.plugins.push(function() {
  this.plugin(&amp;#39;after-compile&amp;#39;, function(compilation, callback){
    for (var file in compilation.assets) if (/\.js$/.test(file) &amp;amp;&amp;amp; !(/^vendor/.test(file))) {
      if (/^(\d+\.)/.test(file)) continue;
      var children = compilation.assets[file].children;
      if (!children) continue;
      // console.log(&amp;#39;preparing &amp;#39; + file + &amp;#39; for async loading.&amp;#39;);
      var source = children[0];
      source._value = source._value.replace(/^webpackJsonp/, &amp;#39;webpackJsonx&amp;#39;);
    }
    callback();
  });
});

mainConfig.plugins.push(function() {
  // clean up old generated files since they are not overwritten due to the hash in the filename
  this.plugin(&amp;#39;after-compile&amp;#39;, function(compilation, callback) {
    for (var file in compilation.assets) {
      var filename = compilation.outputOptions.path + &amp;#39;/&amp;#39; + file;
      var regex = /-[0-9a-f]*.(((\.min)?\.js|\.css)(\.map)?)$/;
      if (regex.test(filename)) {
        var files = glob.sync(filename.replace(regex, &amp;#39;-*$1&amp;#39;));
        files.forEach(function(fn) { if (fn !== filename) fs.unlinkSync(fn); });
      };
    }
    callback();
  });
});

if (PROD) [mainConfig, themesConfig].forEach(function(config) {
  config.plugins.push(new webpack.optimize.UglifyJsPlugin({ minimize: true
    , compress: { warnings: false } }));
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;loaders/ko-loader.js:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Allow KO to work with jQuery without requiring jQuery to be exported to window
module.exports = function(source) {
  this.cacheable();
  return source.replace(&amp;#39;jQueryInstance = window[&amp;quot;jQuery&amp;quot;]&amp;#39;, &amp;#39;jQueryInstance = require(&amp;quot;jquery&amp;quot;)&amp;#39;);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;loaders/non-cacheable-extract-text-webpack-loader.js (required due to a webpack bug):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;var ExtractTextLoader = require(&amp;quot;extract-text-webpack-plugin/loader&amp;quot;);

// we&amp;#39;re going to patch the extract text loader at runtime, forcing it to stop caching
// the caching causes bug #49, which leads to &amp;quot;contains no content&amp;quot; bugs. This is
// risky with new version of ExtractTextPlugin, as it has to know a lot about the implementation.

module.exports = function(source) {
  this.cacheable = false;
  return ExtractTextLoader.call(this, source);
}

module.exports.pitch = function(request) {
  this.cacheable = false;
  return ExtractTextLoader.pitch.call(this, request);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s how jquery-ui-autocomplete.js looks like (the others are similar):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;require(&amp;#39;jquery-ui/ui/autocomplete.js&amp;#39;);
require(&amp;#39;jquery-ui/themes/base/core.css&amp;#39;);
require(&amp;#39;jquery-ui/themes/base/theme.css&amp;#39;);
require(&amp;#39;jquery-ui/themes/base/menu.css&amp;#39;);
require(&amp;#39;jquery-ui/themes/base/autocomplete.css&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;jQuery UI was installed from bower and lives in bower_components/jquery-ui.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how my package.json looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;sample-webpack&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.1&amp;quot;,
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;assets-webpack-plugin&amp;quot;: &amp;quot;^3.2.0&amp;quot;,
    &amp;quot;bower&amp;quot;: &amp;quot;^1.7.7&amp;quot;,
    &amp;quot;bundle-loader&amp;quot;: &amp;quot;^0.5.4&amp;quot;,
    &amp;quot;coffee-loader&amp;quot;: &amp;quot;^0.7.2&amp;quot;,
    &amp;quot;coffee-script&amp;quot;: &amp;quot;^1.10.0&amp;quot;,
    &amp;quot;css-loader&amp;quot;: &amp;quot;^0.14.5&amp;quot;,
    &amp;quot;eco-loader&amp;quot;: &amp;quot;^0.1.0&amp;quot;,
    &amp;quot;es5-shim&amp;quot;: &amp;quot;^4.4.1&amp;quot;,
    &amp;quot;exports-loader&amp;quot;: &amp;quot;^0.6.2&amp;quot;,
    &amp;quot;expose-loader&amp;quot;: &amp;quot;^0.7.1&amp;quot;,
    &amp;quot;extract-text-webpack-plugin&amp;quot;: &amp;quot;^1.0.1&amp;quot;,
    &amp;quot;file-loader&amp;quot;: &amp;quot;^0.8.5&amp;quot;,
    &amp;quot;glob&amp;quot;: &amp;quot;^7.0.0&amp;quot;,
    &amp;quot;imports-loader&amp;quot;: &amp;quot;^0.6.5&amp;quot;,
    &amp;quot;jquery&amp;quot;: &amp;quot;^1.12.0&amp;quot;,
    &amp;quot;jquery-deparam&amp;quot;: &amp;quot;^0.5.2&amp;quot;,
    &amp;quot;jquery-ujs&amp;quot;: &amp;quot;^1.1.0-1&amp;quot;,
    &amp;quot;knockout&amp;quot;: &amp;quot;^3.4.0&amp;quot;,
    &amp;quot;lodash&amp;quot;: &amp;quot;^4.3.0&amp;quot;,
    &amp;quot;merge&amp;quot;: &amp;quot;^1.2.0&amp;quot;,
    &amp;quot;node-sass&amp;quot;: &amp;quot;^3.4.2&amp;quot;,
    &amp;quot;raw-loader&amp;quot;: &amp;quot;^0.5.1&amp;quot;,
    &amp;quot;sass-loader&amp;quot;: &amp;quot;^3.1.2&amp;quot;,
    &amp;quot;script-loader&amp;quot;: &amp;quot;^0.6.1&amp;quot;,
    &amp;quot;sinon&amp;quot;: &amp;quot;^1.17.3&amp;quot;,
    &amp;quot;style-loader&amp;quot;: &amp;quot;^0.13.0&amp;quot;,
    &amp;quot;url-loader&amp;quot;: &amp;quot;^0.5.7&amp;quot;,
    &amp;quot;webpack&amp;quot;: &amp;quot;^1.12.12&amp;quot;,
    &amp;quot;webpack-bundle-size-analyzer&amp;quot;: &amp;quot;^2.0.1&amp;quot;,
    &amp;quot;webpack-dev-server&amp;quot;: &amp;quot;^1.14.1&amp;quot;,
    &amp;quot;webpack-sources&amp;quot;: &amp;quot;^0.1.0&amp;quot;
  },
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;webpack-dev-server -d --colors&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I told you. It took me about a week to perform this migration ;)&lt;/p&gt;
&lt;p&gt;But believe on me. It worths.&lt;/p&gt;
&lt;p&gt;Just run &amp;quot;node_packages/.bin/webpack -w&amp;quot; to enable the watch mode. I&amp;#39;d recommend adding
&amp;quot;node_packages/.bin&amp;quot; to PATH in .bashrc so that you can simply run webpack, bower without
specifying the full path. For the production build, simply run &amp;quot;PROD=1 webpack&amp;quot;.&lt;/p&gt;
&lt;p&gt;Vim users should set backupcopy to yes (default is auto) otherwise the watch mode won&amp;#39;t
detect all file changes as sometimes Vim would move the back-up and create a new copy which
is not detected by the watch mode. See more details &lt;a href=&quot;https://github.com/webpack/webpack/issues/781#issuecomment-95523711&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are experiencing other issues with the watch mode, please check the
&lt;a href=&quot;https://webpack.github.io/docs/troubleshooting.html#webpack-doesn-t-recompile-on-change-while-watching&quot;&gt;Troubleshooting&lt;/a&gt;
section of Webpack documentation.&lt;/p&gt;
&lt;h2&gt;Back-end integration&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;re interested in integrating to Rails, you can stop reading here and jump to the
Rails integration section of &lt;a href=&quot;/en/articles/2016-02-26-improving-spa-loading-time-with-webpack-and-why-sprockets-is-in-your-way#integration&quot;&gt;this article&lt;/a&gt;.
Or if you&amp;#39;d like to get a concrete example. Otherwise, here are the general rules for integrating
to your backend.&lt;/p&gt;
&lt;p&gt;Webpack will generate a webpack-assets.json file due to the assets-webpack-plugin, which
allows us to get the generated bundle full name with the chunk hash included so that we can
use it to pass to the script src attribute. The configuration above would generate 3 bundles.
One for common libraries, other for clients and another for internal users (containing some
additional features not available to client users).&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s some incomplete JavaScript code demonstrating how it works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;APP_ROOT = &amp;#39;/fill/in/here&amp;#39;;

WEBPACK_MAPPING = APP_ROOT + &amp;#39;/app/resources/webpack-assets.json&amp;#39;;

var mapping = JSON.parse(require(&amp;#39;fs&amp;#39;).readSync(WEBPACK_MAPPING));
var vendorPath = mapping[&amp;#39;vendor&amp;#39;][&amp;#39;js&amp;#39;];
var clientPath = mapping[&amp;#39;app/client&amp;#39;][&amp;#39;js&amp;#39;];
var defaultThemePath = mapping[&amp;#39;app/theme-default&amp;#39;][&amp;#39;css&amp;#39;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, it&amp;#39;s used like this in the page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;&amp;lt;%= themePath &amp;quot; %&amp;gt;&amp;quot; /&amp;gt;

  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
    function webpackJsonx(module, exports, __webpack_require__) {
      var load = function() {
        if (window.VENDORS_LOADED)
          return webpackJsonp(module, exports, __webpack_require__);
        setTimeout(load, 10);
      }
      load();
    }
  &amp;lt;/script&amp;gt;

  &amp;lt;!--[if lte IE 8]&amp;gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.5/es5-shim.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;![endif]--&amp;gt;

  &amp;lt;script type=&amp;quot;text/javascript&amp;quot; async defer crossorigin=&amp;quot;anonymous&amp;quot;
    src=&amp;quot;&amp;lt;%= vendorPath %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot; async defer crossorigin=&amp;quot;anonymous&amp;quot;
    src=&amp;quot;&amp;lt;%= clientPath %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Specifying dependencies in the code&lt;/h2&gt;
&lt;p&gt;Webpack has good documentation on how it detects the code dependencies so I won&amp;#39;t get into
the details but will only demonstrate two common usages. One for a regular require, which
will concatenate the code and another for code splitting usage.&lt;/p&gt;
&lt;p&gt;Take this code for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;var $ = require(&amp;#39;jquery&amp;#39;);
var app = require(&amp;#39;app.js&amp;#39;);
app.load();
$(document).on(&amp;#39;click&amp;#39;, &amp;#39;#glossary&amp;#39;, function() {
  require.ensure([&amp;#39;glossary.js.coffee&amp;#39;],
    function() {
      require([&amp;#39;glossary.js.coffee&amp;#39;], function(glossary){ glossary.load() })
    },
    &amp;#39;glossary&amp;#39;
  );
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The require.ensure call is not really required but it allows you to give the lazy chunk a
name which is useful if you want to add other files to the same chunk in other parts
of the code.&lt;/p&gt;
&lt;p&gt;In that example, jquery will go to the vendors bundle, app.js will go into the app bundle
and glossary.js (and any other files added to that chunk) will be lazily loaded by the
application. You can even preload it after initializing the application so that the click
happens faster when the user click on the #glossary element.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;some-numbers&quot;&gt;Some numbers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well, after all this text you must be wondering whether it really worths, so let me show
you some numbers for my application.&lt;/p&gt;
&lt;p&gt;Before those changes, there was a single JS file which was 864 KB (286 KB gzipped). If we
consider the case where the user took 6s to load this file, I think it&amp;#39;s fair to emulate
throttling for Regular 3G (750 kb/s 100 ms RTT) in the Chrome dev tool. I&amp;#39;ve also enabled the
film-strip feature. After disabling cache, the first initial rendering (for the &amp;quot;loading...&amp;quot;
state) happened at 1.16s while the application was fully loaded at 5.26s. It also took 594 ms
to load the 74.2 KB CSS file (17.7KB gzipped).&lt;/p&gt;
&lt;p&gt;Now, after enabling code splitting, and reducing the initial CSS, here are the numbers. Now the
initial &amp;quot;loading...&amp;quot; state was rendered at 499ms and the page was fully loaded at 4.7s. The
CSS file is now 7.2 KB (2.4 KB gzipped) and the JS files are 498 KB (169 KB) gzipped for vendor
and 259 KB (77.8 KB gzipped) for the app bundle. Unfortunately I couldn&amp;#39;t cut much more
application code in my case and most of the code is from vendored libraries, but I think there&amp;#39;s
still room to improve now that webpack is in place. So, whether it worths or not for you to go
through all these changes will depend on the percentage of your code which is required for the
initial full page rendering, and on the frequency you deploy (I deploy very often, so just the
ability of creating a commons bundle is good enough to justify this set-up).&lt;/p&gt;
&lt;p&gt;Just for the sake of completeness, I&amp;#39;ll also show you the numbers with cache enabled and with
throttling disabled.&lt;/p&gt;
&lt;p&gt;With cache enabled, the initial render happened at 496ms and the page was fully loaded by 1.35s
in Regular 3G throttling mode for the webpack version. If I disable throttling, with a 10 Mbps
Internet connection and accessing the NY servers from Brazil I get 354ms for the initial rendering
and 1.22s for the full load. If I disable the cache and throttling I get 445ms and 2.03s.&lt;/p&gt;
&lt;p&gt;For the sprockets version, the initial render happened at 846ms and the page was fully loaded by
1.74s in Regular 3G throttling mode. If I disable throttling I get 553ms for the initial rendering
and 1.48s for the full load. If I disable the cache and throttling I get 740ms and 2.80s.&lt;/p&gt;
&lt;p&gt;Actually, those numbers are both for webpack, as I am no longer able to test the sprockets
version. But I&amp;#39;m calling it sprockets anyway because the first approach should be feasible with
sprockets. But after moving to webpack I was able to more easily extract only the parts we use
from jQuery UI and replace underscore with lodash to use only the parts we need and I&amp;#39;ve also
got rid of some other big libraries in the process. Before those changes the app bundle was
1.2MB minified (376KB gzipped), so I was able to reduce the amount of transferred data to about
65% of what it used to be, but it wouldn&amp;#39;t be fare to compare those numbers because in theory
it should be possible to achieve a lot of this reduction without dropping sprockets.&lt;/p&gt;
&lt;p&gt;But in our case, we were able to improve the page loading speed after moving to webpack even
before applying code splitting due to the flexibility it provides us which I find easier to
take advantage of when compared to how we used the assets from sprockets.&lt;/p&gt;
&lt;p&gt;And now we&amp;#39;re able to use the source-maps for both debugging in the production environment but
specially to understand the stack-traces when JS exceptions are thrown.&lt;/p&gt;
&lt;p&gt;If you have any questions please write them in the comments or send me an e-mail and I&amp;#39;ll try
to help if I can.&lt;/p&gt;
</content:encoded></item><item><title>Scripts loading trade-offs: a performance analysis</title><link>https://rosenfeld.page/articles/2016_02_29_scripts_loading_trade_offs_a_performance_analysis/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2016_02_29_scripts_loading_trade_offs_a_performance_analysis/</guid><pubDate>Mon, 29 Feb 2016 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This has been written to serve as some background for two other articles focused on SPA performance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/en/articles/2016-02-29-getting-an-spa-to-load-the-fastest-possible-way-and-how-webpack-can-help-you&quot;&gt;Getting an SPA to load the fastest possible way (and how Webpack can help you)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/en/articles/2016-02-26-improving-spa-loading-time-with-webpack-and-why-sprockets-is-in-your-way&quot;&gt;Improving SPA loading time with webpack (and why Sprockets is in your way)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#39;ve been developing Single Page Applications (SPA) since 2009 and I can tell you something for
sure. Developing web applications is hard! If you are a full-stack developer like me you have to
learn about relational databases, caching technology (Redis, Memcached), a server-side language
and framework, sometimes other kind of databases, full-text search (Solr, ElasticSearch),
server configuration and automation tools (Chef/Puppet/Ansible), deploy tools (Capistrano),
continuous integration, automatic test coverage, network infrastructure, http proxy configuration,
load balancers, back-up and monitoring services, just to name a few.&lt;/p&gt;
&lt;p&gt;But even if we leave all these technologies out and only focus on front-end development, then,
it&amp;#39;s still hard! JavaScript is not a great language and I certainly do not like the language at all
but we don&amp;#39;t really have any affordable options since it&amp;#39;s all web browsers understand and if you
want your application to load fast you must use JavaScript and you must learn it and learn it well.&lt;/p&gt;
&lt;h2&gt;Code modularization in JavaScript&lt;/h2&gt;
&lt;p&gt;But particularly the lack of some sort of require/import mechanism built into the language is
the worst part of the language by far and the reason why people spend so many time just to figure
out some way to implementing modularization as the code gets big and this will often happen soon
when implementing an SPA.&lt;/p&gt;
&lt;p&gt;On the other side, the require mechanism when applied to a client-server architecture where the
code is stored in the server-side (which is how browsers work) is much trickier than it is for most
languages which assume the code is locally available. In such architecture, if you want your code
to load as fast as possible you should be worried about transferring only the required bits as you
need them. Requiring code on demand is possible in many languages, like Ruby, but in JavaScript it
is even more tricky because JavaScript doesn&amp;#39;t allow threaded code (workers only popped up very
recently) and works by processing events, one at a time, the so called async programming.&lt;/p&gt;
&lt;p&gt;This means a require in JavaScript should also work asynchronously (Node.js is a different beast
as it allows some code to work synchronously by blocking the code execution until the operation
of the function is finished while any I/O operation in the browser is implemented asynchonously).
I just don&amp;#39;t think this is an excuse for JavaScript not providing such mechanism out of the box,
but this is not an article to say bad things about JavaScript. There are already tons of those
out there, I&amp;#39;m just explaining why modularization is a complex subject in JavaScript and front-end
development.&lt;/p&gt;
&lt;h2&gt;Solutions to JS modularization&lt;/h2&gt;
&lt;p&gt;There are many attempts to implement code modularization in JavaScript. I won&amp;#39;t get into the
details since there are many articles covering only this subject. If you are curious you can search
about CommonJS, Require.js, AMD and JavaScript modularization in general. I&amp;#39;m just going to review
the solutions from a higher level perspective, and talk about their trade-offs as it&amp;#39;s important
to understand them in order to explain how to load applications fast.&lt;/p&gt;
&lt;h2&gt;Sequence of script tags&lt;/h2&gt;
&lt;p&gt;When JavaScript was first introduced in Netscape people would simply add each module to the page
by adding a script tag in the header for each module. This will block the page rendering until the
scripts are downloaded and a user navigating to the site will see a blank page until all script
sources are downloaded and executed. When you have big scripts and bad network bandwidth (which
is specially true for mobile devices running on 2G, 3G and even 4G) it leads to a really bad
user experience.&lt;/p&gt;
&lt;p&gt;The main advantage of this approach is that it&amp;#39;s easy to set up and understand, since the scripts
are executed in the specified order of the script tags. If your links and buttons depend on the
scripts to work properly (which is usually the case) then, by putting the scripts in the document
head you wouldn&amp;#39;t have to worry about that. This is the simplest solution to develop. But it&amp;#39;s
also the one that will perform worst.&lt;/p&gt;
&lt;p&gt;Even if you decide to put your scripts in the end of the page, it&amp;#39;s still a problem if you want
your page to load really fast. That&amp;#39;s because it will delay the DOMContentLoaded and Load DOM
events and if part of your code is listening on those events it means they will have to wait until
all scripts are downloaded and executed. If your code doesn&amp;#39;t depend on those events and if your
page is fully functional even before the scripts are downloaded (links and buttons work as expected)
then it might be a good strategy for your case, if you target browsers supporting HTTP 2 since
it allows you to have great control over per module caching so that if your users visit your
application very often and you only change a few files in a new deploy then those users would only
have to download the changed files with proper caching headers in place.&lt;/p&gt;
&lt;p&gt;But most browsers will limit the amount of concurrent resources download, which means that if
your application depend on many script tags they won&amp;#39;t be all downloaded in parallel, which can
introduce some additional time to the application loading.&lt;/p&gt;
&lt;p&gt;Another drawback for the approach of putting the scripts in the end of the document body is that
their download will only start after the document download is mostly completed. This is not a big
deal if your document is small, but if takes 1 second just to finish downloading your main document
it means your scripts will only start to be downloaded 1s after the user requests your application
to be loaded, which means your application may take an extra second to load than it should.&lt;/p&gt;
&lt;h3&gt;Async scripts&lt;/h3&gt;
&lt;p&gt;An alternative to putting the script tags at the end of the body is to keep them in the head but
flag them as async scripts (or defer too if you target older IE which do not support the async
attribute - even though defer and async behave differently defer is still better than the default
script blocking behavior). The main advantage over scripts in the bottom is that the scripts
will start downloading very soon without blocking the page rendering or the DOM load events (defer
works a bit differently than async with regards to those events).&lt;/p&gt;
&lt;p&gt;However, your scripts must be async safe for that to work. For example, you can&amp;#39;t load jquery and
jquery-ui from CDN in two async script tags because if jquery-ui is loaded before jquery it will
fail to run as it assumes jQuery is loaded already.&lt;/p&gt;
&lt;p&gt;This strategy is usually used in combination with scripts custom bundles. It could be a single
bundle, which is easier to implement or if multiple bundles are created they should be prepared to
wait for their dependencies to be loaded before running its code.&lt;/p&gt;
&lt;h3&gt;Dynamically created script tags (Injected Scripts)&lt;/h3&gt;
&lt;p&gt;Script tags created dynamically do not block and could be used to implement some async require,
which is the strategy adopted by Require.js and similar frameworks. Taking care of implementing
this strategy correctly while still supporting old browsers is not an easy task and that&amp;#39;s why
there are many frameworks providing this feature and why I think it&amp;#39;s a big failure of JavaScript
to not provide such feature out of the box.&lt;/p&gt;
&lt;p&gt;There are some different strategies for using technique though. One might simply add all required
scripts dynamically to ensure they won&amp;#39;t block page rendering (although I think async scripts are
cleaner in this case) or they could be used to dynamically load code on demand, which I will refer
as code splitting in this article from now on.&lt;/p&gt;
&lt;p&gt;At first it may sound like a good idea to load just the code your application needs so far, as they
are needed because it reduces the amount of bytes transferred, but it also increases the number
of requests, and more importantly, it shifts the moment when that code download starts.&lt;/p&gt;
&lt;p&gt;If you concatenate all this code and put it in an async script on head it will load the application
faster, otherwise even if you started the download of all dependencies in parallel, it would be
equivalent to putting the script tags in the end of the body which means your application will
load 1s late when compared to when it should finish load in the optimal case (see the last
comment in the &amp;quot;Sequences of script tags&amp;quot; section).&lt;/p&gt;
&lt;p&gt;But it&amp;#39;s more tempting to load each module when they are needed when using this strategy, which
makes things even worse. If you need module A, which depends on B, which depends on C the browser
will have to finish downloading A to figure out it should also ask to download B and only after
B is finished loading the request to C would start. It may not be always obvious that A depends
on both B and C so that you could require A, B and C at the same time when we are talking about
real code. That&amp;#39;s why Require.js offers a bundling tool to deliver an optimized JS to production
environments.&lt;/p&gt;
&lt;p&gt;Creating script tags inside scripts has a performance issue, though, which is explained in depth
&lt;a href=&quot;https://www.igvita.com/2014/05/20/script-injected-async-scripts-considered-harmful/&quot;&gt;here&lt;/a&gt;.
Since the scripts could interact with CSSOM, it means it will block until all previous CSS
resources have finished downloading, introducing an unnecessary latency. Async script tags are
preprocessed by the browsers and their download will start immediately (just like regular
script tags with the src attribute, the difference being that async tags won&amp;#39;t block the DOM).
That&amp;#39;s why we should prefer async script tags over dynamically created scripts for the initial
application loading process (loading code on demand is a separate case).&lt;/p&gt;
&lt;h3&gt;Scripts bundling - single bundle&lt;/h3&gt;
&lt;p&gt;This is considered a best practice by many currently and several tools adopt this strategy,
including Sprockets, the resources build tool integrated with Ruby on Rails default stack.&lt;/p&gt;
&lt;p&gt;How the bundles are built will depend on the bundler tool. Sprockets require the resources to
specify their dependencies as special comments in the top of each resource (JS or CSS). Other
tools use the AMD or CommonJS require syntax for example to specify the dependencies and will
parse the JS to find them, which is more complex than the strategy used by Sprockets, but on the
other side allow more powerful features, like code splitting (more on that when I&amp;#39;ll talk about
webpack). There&amp;#39;s also another technique of specifying the dependencies outside the resources
themselves, which is used by the Grails resources plugin for example, or by some build tools
similar to Make.&lt;/p&gt;
&lt;p&gt;Which strategy is better will also depend on personal taste. Particularly I prefer to specify
the dependencies directly in the code rather than in a separate file, like it happens with Grails
resources plugin. But when code splitting is desirable it&amp;#39;s not just a matter of taste.
Implementing code splitting while using Sprockets would require a huge amount of effort for
example. That&amp;#39;s why I think Sprockets doesn&amp;#39;t suite big SPA and the reason why it should be
replaced with a better tool.&lt;/p&gt;
&lt;p&gt;Such bundling tools are usually able to perform other preprocessing before generating the final
optimized resource, including minifying them with uglifyjs to reduce the download size and
compiling from other languages to JS and CSS (after all, as I said, many people dislike those
languages and fortunately there are better alternatives out there when you can use preprocessors
and transpilers).&lt;/p&gt;
&lt;p&gt;By having a single JS file to download and run you reduce the amount of concurrent requests to
your server and you can even serve them through a CDN to improve it even more as the limit of
concurrent connections work in a per domain basis (even though it may not be best to use a CDN
if HTTP 2 is enabled and under some conditions).&lt;/p&gt;
&lt;p&gt;For a first not cached request this is probably the strategy with best results if we consider the
bundle contains only the required code for the initial page loading, which is hardly the case.&lt;/p&gt;
&lt;p&gt;So, here are some drawbacks for this approach. Usually all code is bundled in a single file,
creating big files which take a while to finish downloading, even if it only happens once until
the next deploy. And it gets worse if you are able to deploy very often. If you deploy every day
then the user will often request a request which is not cached. And I wouldn&amp;#39;t say this is an
unrealistic scenario for many healthy products.&lt;/p&gt;
&lt;p&gt;This might be a good enough solution if your bundle is small or if you deploy once in a month or
each 6 months and most of your user access are cached ones, but if you are targeting a great
experience for first time users, you should look for a better alternative.&lt;/p&gt;
&lt;h3&gt;Script bundling - multiple bundles&lt;/h3&gt;
&lt;p&gt;Even if you deploy often, it&amp;#39;s likely that your vendored libraries don&amp;#39;t change that often. So
it may make sense to pack your vendored libraries in a separate bundle so that it would be cached
most of the times even after new deploys. Since you should be loading the vendors and application
bundles asynchronously you must add some simple code to ensure the application code would only
run after the vendors bundle has finished loading.&lt;/p&gt;
&lt;p&gt;This will usually add just a little overhead for the first user access when compared to the single
bundle but on the other hand it will often speed up other page loads after a new version is
deployed while the vendors bundle hasn&amp;#39;t changed.&lt;/p&gt;
&lt;p&gt;If your application bundle only contains code for the initial page rendering and implements lazy
code loading as the user takes action (code splitting) this gets even better.&lt;/p&gt;
&lt;p&gt;In the remaining sections I&amp;#39;ll show how webpack enables such strategy to be implemented and will
compare it to Sprockets since I have switched from Sprockets to Webpack and should be able to
highlight the weak and strong points of each.&lt;/p&gt;
&lt;h2&gt;Server-side vs client-side template rendering&lt;/h2&gt;
&lt;p&gt;Feel free to skip this subsection if you don&amp;#39;t care about this subject.&lt;/p&gt;
&lt;p&gt;Some respected developers often state the clients should get a fully rendered HTML partial from
the server and simply add it to some container or replace its content trying to convince us that
this is the best and fastest approach. To give you one example, David, the creator of Rails,
&lt;a href=&quot;https://signalvnoise.com/posts/3697-server-generated-javascript-responses&quot;&gt;writes about the reasons why he thinks this is the best approach&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Benefit #1 is &amp;quot;Reuse templates without sacrificing performance&amp;quot;. While I agree with the reuse
part in the case the content should also be rendered in the server-side and then updated with JS,
I wouldn&amp;#39;t blindly trust the &amp;quot;without sacrificing performance&amp;quot; part. Reuse may not be a problem
for many SPA, including the one I maintain, so we should evaluate whether there&amp;#39;s any performance
difference for both approaches in a per case basis and which one is actually faster.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s important to understand the full concepts to get the full picture so that you can pick the
right choice. First, I&amp;#39;d like to point out that I don&amp;#39;t agree with David&amp;#39;s terminology: &amp;quot;unless
you&amp;#39;re doing a single-page JavaScript app where even the first response is done with
JSON/client-side generation&amp;quot;. SPA should mean an application that won&amp;#39;t leave the initial page
and use XHR to update the view. Both approaches apply to SPA in my opinion.&lt;/p&gt;
&lt;p&gt;Then, you have to understand what is the specific case David is recommending you to render in the
server-side and which I would agree. If your application is able to render an initial view, which
is useful and functional even before your JS code has finished loading, then I&amp;#39;d also recommend
you to render it in the server-side. But please notice that even this approach won&amp;#39;t always be the
fastest. It will be the fastest when the static resources are not in cache. But if they are cached
the application can load much faster if the rendering is performed in the client-side depending
on the template and data. So, it will depend on the kind of access you are optimizing to: cached
resources or first user access.&lt;/p&gt;
&lt;p&gt;You&amp;#39;ll notice I&amp;#39;m inviting you to think about the reasons behind each statement because they often
suppose something which is not always true, so you should understand to see whether it applies to
your case or not. Much more often there are trade-offs in all choices and that&amp;#39;s the reason I try
to provide you context around every statement I do in this article.&lt;/p&gt;
&lt;p&gt;In that same article we can extract another example of such statement which is not always true:&lt;/p&gt;
&lt;p&gt;&amp;quot;While the JavaScript with the embedded HTML template might result in a response that&amp;#39;s marginally
larger than the same response in JSON (although that’s usually negligible when you compress with
gzip)&amp;quot;. This is not always true. If you are working with big templates where just a small percent
of it depend on dynamic data, transferring that data with JSON will often be much faster. Or if
you are transferring some big table where the cells content (the dynamic part) represents only
about 30% of the total HTML, chances are that it will be much faster to transfer the data as JSON.&lt;/p&gt;
&lt;p&gt;I&amp;#39;d also like to notice that if your application depend on your resources to be loaded to behave
properly (so that links work, menu, tabs, and so on), then I can&amp;#39;t see any great advantages on
rendering the initial template in the server-side since you wouldn&amp;#39;t be able to display it to the
user anyway because it wouldn&amp;#39;t be functional until the code is fully loaded. In that case (which
is the case for the SPA&amp;#39;s I have worked with since 2009) I&amp;#39;d suggest to create a minimal document
with a basic layout (footer, header, ...) which is fully functional without JS and some message
&amp;quot;Loading application... please wait&amp;quot; until the code is fully loaded even if that message would be
displayed just for 1 or 2 seconds... With the techniques suggested in this article, you would be
able to provide such &amp;quot;Loading application...&amp;quot; state to the user in within half a second, much
faster than a big full HTML document leading the user to think the application is very responsive
even in mobile devices, even if it will require a few extra seconds to finish loading the
application.&lt;/p&gt;
&lt;p&gt;Overall I have been noticing that the actual reason why most people prefer to render in the
server-side is because they don&amp;#39;t like JS or feel more comfortable with their back-end language
and tools. I don&amp;#39;t enjoy programming in JS either, but it shouldn&amp;#39;t matter if the goal is to
provide the best user experience. I had to learn JS and learn it well. I&amp;#39;ve spent a lot of time
to learn a lot about JS and browser performance and much more even though I don&amp;#39;t enjoy the
language nor I do enjoy IE8, but I have to learn about it because our application sadly still has
to support it. So here is my advice for those of you that avoid JS at all costs just because
you don&amp;#39;t like it. Get over it.&lt;/p&gt;
&lt;p&gt;On the other hand, there are some developers which are exactly the opposite. They prefer working
with JS so much that they will also run the back-end on Node.js. There are some cases where the
&amp;quot;Rails Way&amp;quot; (or DHH way if you prefer) is the right one. For example, if your application is
publicly available rather than only for authenticated users, you&amp;#39;d probably want it to be indexed
by search engines, like Google. Even though Google engine can now understand JS, I&amp;#39;d still
recommend you to render those pages in the server-side if possible. Also, in those cases it&amp;#39;s very
likely a user would like to bookmark some specific page or send the link to someone and this works
more like a traditional web site than a real application. This is exactly what Turbolinks was
designed for. If Turbolinks code is not loaded yet the application should keep working as expected
but switching to another page may take longer than when Turbolinks code is loaded. That&amp;#39;s the kind
of application I would recommend adopting DHH&amp;#39;s suggestion. If that&amp;#39;s your case, I&amp;#39;m afraid you
won&amp;#39;t be much interested in the content of this article as this article is focused on real
applications rather than optimizations over traditional web sites, which is what Turbolinks does.&lt;/p&gt;
&lt;h3&gt;XHR requests and caching&lt;/h3&gt;
&lt;p&gt;One of the arguments for the server-rendering approach is that they can be cached. But XHR
requests can be cached too. But they require some additional work since caching is usually
disabled by default by libraries like jQuery, for good reasons of course.&lt;/p&gt;
&lt;p&gt;The main problem with allowing cache in XHR requests is that the browser will leave it to the
code to handle caching, which can be not always possible and will often require quite some code
to handle it properly. I enable caching of XHR requests in the application I maintain and it
worths in our case, but the sad news is that it&amp;#39;s only useful if you make some request at least
twice as the first request can&amp;#39;t be retrieved from cache unless you enable localStorage and add
some extra code... This article is already too long so I won&amp;#39;t explain the details, but if you
are curious and want to see some code, just leave a comment and I may consider writing another
article just to explain how this works in practice.&lt;/p&gt;
&lt;p&gt;When you perform a regular request to the server, the browser will send the etags or
if-modified-since headers when it has a cached copy and if the server responds with 304 (Not
Modified) it will load that cached response transparently to the user. But for XHR requests
your code would have to handle the 304 status but it won&amp;#39;t get a copy of the cached content from
the browser, so it&amp;#39;s not that useful. It&amp;#39;s only useful if you have stored a the response of
some previous request to the same address so that you could use that response when handling a
304 status response. It&amp;#39;s sad that the browser doesn&amp;#39;t provide a better mechanism for conditional
caching of XHR requests or even handle them transparently.&lt;/p&gt;
&lt;p&gt;So, for the initial XHR requests, they have a point for rendering in the server-side to take
advantage of conditional caching tags but as you can see in the next sections, such XHR requests
for the initial page loading should be avoided anyway and it&amp;#39;s possible to cache the initial
data in separate script tags loaded async (assuming the initial data is cacheable, or part of it).
Keep reading.&lt;/p&gt;
&lt;h2&gt;Initial client-side rendering performance considerations&lt;/h2&gt;
&lt;p&gt;If you decide to render your templates in the client-side, you must consider how to make it
so without sacrificing performance. Suppose your application relies on some JSON to render the
initial page. It&amp;#39;s usual for the application to perform some AJAX requests upon the application
load to finish loading the page, and you should avoid this technique if you want your application
to load the fastest possible way.&lt;/p&gt;
&lt;p&gt;The reason is that the AJAX request will only happen after your application code is downloaded
and executed, which means it will add some overhead while that data could be downloaded in parallel
or embedded in the main document. Let&amp;#39;s discuss each case.&lt;/p&gt;
&lt;h3&gt;Embedding all data required for the initial loading in the document body&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s possible to avoid those extra AJAX requests upon the initial load by embedding all data you
need in script tags in the end of your document body, and it should be fine if your data is small
and shouldn&amp;#39;t prevent your main page from being cacheable.&lt;/p&gt;
&lt;p&gt;If your main document would be cacheable otherwise, or if your data is big enough to require some
considerable extra time to finish loading the main document, which would delay some DOM load events,
then this technique may not be your best bet.&lt;/p&gt;
&lt;p&gt;I don&amp;#39;t recommend permanent caching (even if for an specific time span) for an SPA main document.
In case it has some bug and need to be fixed urgently, a permanent cached copy will prevent that
for some users. But it doesn&amp;#39;t mean the main document can&amp;#39;t be cached. Your application may use
Etags or if-modified-since headers.&lt;/p&gt;
&lt;p&gt;Suppose the main document could benefit from such caching while your extra data would invalidate
such caching due to its dynamic nature. In that case, you should consider whether embedding it
in the end of the document body would still be a good idea. As you can see in the next subsection,
it&amp;#39;s not the only alternative.&lt;/p&gt;
&lt;p&gt;On the other side, if your data is big but a great part of it is cacheable, than it&amp;#39;s also a good
idea to extract the cacheable part and load it separately so that you could take advantage of
some caching to speed up the next application loadings.&lt;/p&gt;
&lt;h3&gt;Using separate async scripts to load initial data&lt;/h3&gt;
&lt;p&gt;The alternative to embed the initial data in the application document is to load that data in
async script tags in the header. This way, the data would start downloading very soon, in parallel
with the other required data. In that case, you should either wrap the JSON data in a function call
(JSON-P like solution) or add some custom code to store that data in some global variable
(window.initialData for instance) or whatever makes sense to your application (attaching data to
your body element or anything you could imagine).&lt;/p&gt;
&lt;p&gt;When combined to code splitting, where multiple scripts are loaded concurrently, I&amp;#39;d recommend the
JSON-P style to avoid some time-based polling with setTimeout to check until all pieces have been
downloaded and evaluated. Here&amp;#39;s how the document head could look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;app.css&amp;quot; /&amp;gt;
&amp;lt;!-- this script could be external but should be sync rather than async. Since
it&amp;#39;s small, I&amp;#39;d usually embed it, although it&amp;#39;s avised that your server-side
technology would minify it before embedding it, but it&amp;#39;s outside the scope of
this article explaining how to do that. --&amp;gt;
&amp;lt;script&amp;gt;
  ;(function() {
    var appSettings = { loadedContent: [], handlers: {}, loaded: {} }
    window.onContentLoaded = function(id, handler, once) {
      var alreadyLoaded = appSettings.loaded[id];
      if (alreadyLoaded &amp;amp;&amp;amp; once) return;
      if (!alreadyLoaded) {
        appSettings.loadedContent.push(id);
        appSettings.loaded[id] = true;
        if (handler) {
          if (once) handler(appSettings);
          else appSettings.handlers[id] = handler;
        }
      }
      for (var i in appSettings.handlers) appSettings.handlers[i](appSettings);
    }
  })()
&amp;lt;/script&amp;gt;
&amp;lt;!-- remaining async scripts: --&amp;gt;

&amp;lt;script async defer src=&amp;quot;/static/vendors-a98fed.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script async defer src=&amp;quot;/static/app-76ea865b.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script async defer src=&amp;quot;/app/initial-data.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As usual, any static builds should contain some content hash in the filename so that it could be
permanently cached and your initial-data request(s) should use other cache headers like etags and
if-modified-since when possible.&lt;/p&gt;
&lt;p&gt;Each script could call onContentLoaded passing an id for that script (&amp;#39;vendors&amp;#39;, &amp;#39;app&amp;#39;,
&amp;#39;initial-data&amp;#39;) and an optional handler to be called whenever some resource is loaded (or just
once if the once parameter is true). The handler gets the appSettings instance which can be used
to check which resources have been loaded already for deciding when to take action. This way no
polling should be required.&lt;/p&gt;
&lt;h4&gt;Security concerns&lt;/h4&gt;
&lt;p&gt;When loading user-sensitive data in the initial-data scripts one should be concerned about
security to not allow cross-site script attacks to steal user&amp;#39;s data. I think it should be enough
to check for the Referer HTTP header and compare it to a white-list of domains allowed to load
that script. If you want to use a CDN for these requests you should set up your CDN to forward
the Referer header in that case. It&amp;#39;s always a good idea to check with your security team if you
have one. If you think the proposed solution here is not good enough or if you have other
suggestions, please comment or send me an e-mail. I&amp;#39;d love your feedback.&lt;/p&gt;
</content:encoded></item><item><title>Improving SPA loading time with webpack (and why Sprockets is in your way)</title><link>https://rosenfeld.page/articles/2016_02_26_improving_spa_loading_time_with_webpack_and_why_sprockets_is_in_your_way/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2016_02_26_improving_spa_loading_time_with_webpack_and_why_sprockets_is_in_your_way/</guid><pubDate>Fri, 26 Feb 2016 17:25:00 GMT</pubDate><content:encoded>&lt;p&gt;This should be seen as a 3-parts series and it was previously published as all those articles
bundled together but the article became too long. I&amp;#39;ve published the server-side framework
agnostic part &lt;a href=&quot;/en/articles/2016-02-29-getting-an-spa-to-load-the-fastest-possible-way-and-how-webpack-can-help-you&quot;&gt;here&lt;/a&gt;
and that part itself require some background on how scripts can be loaded and the trade-offs
for each approach
&lt;a href=&quot;/en/articles/2016-02-29-scripts-loading-trade-offs-a-performance-analysis&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This article will focus on how to implement those techniques in Rails and how it compares to
Sprockets, the de facto solution, or the Rails Assets Pipeline.&lt;/p&gt;
&lt;h2&gt;Switching away from Sprockets&lt;/h2&gt;
&lt;p&gt;As I mention in the &lt;a href=&quot;/en/articles/2016-02-29-getting-an-spa-to-load-the-fastest-possible-way-and-how-webpack-can-help-you&quot;&gt;other related article&lt;/a&gt;,
I realized that for our already optimized application (as far as Sprockets allows it to be) to
take one step further we&amp;#39;d have to introduce code splitting and only load the code required for
the initial state initially.&lt;/p&gt;
&lt;p&gt;I could have implemented code splitting on my own, since Sprockets doesn&amp;#39;t support it out of
the box, but by that time I was already feeling Sprockets was in my way for a long time for
many other reasons, like lack of source-maps or ES6/Babel support and bad integration with
the npm packages system and the Node.js community as a whole. About a month after I realized
I should be replacing it with a better build system and started to study webpack I read the
rails-assets.org team announcing they would stop supporting that effort by the end of 2017,
which confirmed I was in the right direction as their team came to the same conclusion as I
that it wasn&amp;#39;t the best approach for integrating with the JS ecosystem and also because I
would no longer be able to count on rails-assets.org for the bower integration after 2018
(and that integration was never perfect anyway).&lt;/p&gt;
&lt;p&gt;I&amp;#39;d love to be able to tell you how to migrate from Sprockets to Webpack in baby steps but after
thinking about it for a long time I couldn&amp;#39;t figure out some way to do it gradually. It took me
about a week to finish the migration of several sources and libraries to webpack and fortunately
I had a calm week after our last deploy that would allow me to make this change happen. Before
that I have invested another week or two investigating about webpack and other alternatives to
be sure this was the right direction for me to take. If your application is big and has lots of
modules be warned that the transition to webpack is not a trivial one. But it&amp;#39;s not hard either,
but you need some time available to perform it and no other development should take place during
the transition to avoid many conflicts which would take even more time to resolve.&lt;/p&gt;
&lt;p&gt;However, I can recommend that the first step would be to make your libraries available through
webpack, so that you can get used to it at the same time you can get rid of the rails-assets.org
gems by replacing them with npm or bower packages since this can be done in parallel with other
activities and with baby steps. At least, this is what I did and it took me about 2 days to move
away from rails-assets.org gems to webpack managed libraries.&lt;/p&gt;
&lt;h3&gt;Webpack drawbacks when compared to Sprockets&lt;/h3&gt;
&lt;p&gt;There are basically 3 points where Sprockets is better than the Webpack approach:&lt;/p&gt;
&lt;p&gt;1 - Sprockets supports persistent caching when compiling assets, which allows faster deploy times
when you just change a few assets;
2 - Requests to the document will block until all changed assets compilation has finished. 
Even though the watch mode of webpack is pretty fast (assuming uglify is not enabled in
development mode), it may take 2 or 3 seconds to update the bundles after some file is changed.
If you try to refresh a page just after making the change, it&amp;#39;s possible it won&amp;#39;t load the
latest changes, while Sprockets will block the request until the generated assets are updated,
which is nicer than checking the console to see if the compilation has finished;
3 - Any errors in the assets are better displayed when loading the document due to the great
integration sprockets has with Rails;&lt;/p&gt;
&lt;p&gt;On the other side, Sprockets has so many drawbacks that I won&amp;#39;t list all of them here to not
repeat myself. Just read the remaining of this article and the other mentioned ones. Just to
name a few: lack of support for code splitting, source-maps, ES6/Babel, NPM/Bower integration
(with regards to evaluating requires). Integration with several client-side test frameworks can
also be made much easier with webpack, by specifying all dependencies in a separate webpack
configuration without having to export anything to the global context... It also allows your
front-end code to be managed independently, without any dependencies on Rails which may be
desired for some teams where the front-end team would prefer to work independently from the
back-end team.&lt;/p&gt;
&lt;p&gt;Having said that, by no means I regret moving from Sprockets to Webpack. After the first week I
created this Rails app to replace a Grails app I inherited, I decided to switch from
ActiveRecord to Sequel. I was already a Sequel fan but Arel had just arrived to AR by that time
and I decided to give it a try but gave up after one week. Replacing AR with Sequel was the best
decision I took for this project and I think moving from Sprockets to Webpack will prove to be
the second best choice I&amp;#39;ve made for this project.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;integration&quot;&gt;Integration Webpack with Rails&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Follow the instructions described in &lt;a href=&quot;/en/articles/2016-02-29-getting-an-spa-to-load-the-fastest-possible-way-and-how-webpack-can-help-you#set-up-instructions&quot;&gt;this other generic article about Webpack&lt;/a&gt;
and then proceed with these instructions.&lt;/p&gt;
&lt;p&gt;Webpack will generate a webpack-assets.json file due to the assets-webpack-plugin, which
allows us to get the generated bundle full name with the chunk hash included so that we can
use it to pass to the script src attribute.&lt;/p&gt;
&lt;p&gt;I do that by adding some methods to application_helper.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;json&amp;#39;

WEBPACK_MAPPING = &amp;quot;#{Rails.root}/app/resources/webpack-assets.json&amp;quot;

module ApplicationHelper

  def webpack_resource_js_path(resource_name)
    webpack_resource_path resource_name, &amp;#39;js&amp;#39;
  end

  def webpack_resource_css_path(resource_name)
    webpack_resource_path resource_name, &amp;#39;css&amp;#39;
  end

  def webpack_stylesheet_link_tag(resource_name)
    stylesheet_link_tag webpack_resource_css_path(resource_name)
  end

  private

  def webpack_resource_path(resource_name, type)
    webpack_mapping[resource_name][type]
  end

  def webpack_mapping
    @webpack_mapping ||= JSON.parse File.read WEBPACK_MAPPING
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, it&amp;#39;s used like this in the page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;  &amp;lt;%= webpack_stylesheet_link_tag &amp;quot;app/theme-#{@theme}&amp;quot; %&amp;gt;
  &amp;lt;%= render partial: &amp;#39;/common/webpack_boot&amp;#39; %&amp;gt;
  &amp;lt;%= javascript_include_tag webpack_resource_js_path(&amp;#39;vendor&amp;#39;),
        defer: &amp;#39;defer&amp;#39;, async: &amp;#39;async&amp;#39;, crossorigin: &amp;#39;anonymous&amp;#39; %&amp;gt;
  &amp;lt;% script = webpack_resource_js_path(current_user.internal? ? &amp;#39;app/internal&amp;#39; : &amp;#39;app/client&amp;#39;) %&amp;gt;
  &amp;lt;%= javascript_include_tag script, defer: &amp;#39;defer&amp;#39;, async: &amp;#39;async&amp;#39;, crossorigin: &amp;#39;anonymous&amp;#39; %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;/common/_webpack_boot.html.erb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
  function webpackJsonx(module, exports, __webpack_require__) {
    var load = function() {
      if (window.VENDORS_LOADED)
        return webpackJsonp(module, exports, __webpack_require__);
      setTimeout(load, 10);
    }
    load();
  }
&amp;lt;/script&amp;gt;
&amp;lt;!--[if lte IE 8]&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.5/es5-shim.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;![endif]--&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;ve also enhanced the assets:precompile task so that you don&amp;#39;t have to change your deploy
scripts:&lt;/p&gt;
&lt;p&gt;lib/tasks/webpack.rake:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;namespace :webpack do
  webpack_deps = [&amp;#39;resources:sprites&amp;#39;, &amp;#39;js:routes&amp;#39;, &amp;#39;webpack:generate_settings_js&amp;#39;,
    &amp;#39;webpack:install&amp;#39;]

  desc &amp;#39;build webpack resources&amp;#39;
  task build: webpack_deps do
    puts &amp;#39;building webpack resources...&amp;#39;
    system(&amp;#39;cd app/resources &amp;amp;&amp;amp; PROD=1 node_modules/.bin/webpack --bail &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&amp;#39;) or
      raise &amp;#39;webpack build failed&amp;#39;
    puts &amp;#39;resources successfully built&amp;#39;
  end

  desc &amp;#39;webpack watch&amp;#39;
  task watch: webpack_deps do
    system &amp;#39;cd app/resources &amp;amp;&amp;amp; node_modules/.bin/webpack -w&amp;#39;
  end

  task :install do
    system &amp;#39;cd app/resources &amp;amp;&amp;amp; npm install &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&amp;amp; node_modules/.bin/bower install &amp;gt;/dev/null 2&amp;gt;&amp;amp;1&amp;#39; or
      puts &amp;#39;webpack install failed&amp;#39;
  end

  task :generate_settings_js do
    require &amp;#39;erb&amp;#39;
    require &amp;#39;fileutils&amp;#39;
    FileUtils.mkdir_p &amp;#39;app/resources/src/js/app&amp;#39;
    File.write &amp;#39;app/resources/src/js/app/settings.js&amp;#39;,
      ERB.new(File.read &amp;#39;app/assets/javascripts/app/settings.js.erb&amp;#39;).result(binding)
  end
end

Rake::Task[&amp;#39;assets:precompile&amp;#39;].enhance [&amp;#39;webpack:build&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;ve also moved the sprites generation from compass to a custom script I created:&lt;/p&gt;
&lt;p&gt;lib/tasks/sprites.rake:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;namespace :resources do
  desc &amp;#39;generate theme sprites&amp;#39;
  task :sprites do
    `front-end/generate-sprites.rb`
  end

  # TODO: Fix the need for this in Capistrano
  task :generate_fake_manifest do
    `touch public/assets/manifest.txt`
  end
end

Rake::Task[&amp;#39;assets:precompile&amp;#39;].enhance [&amp;#39;resources:sprites&amp;#39;, &amp;#39;resources:generate_fake_manifest&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;front-end/generate-sprites.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;#!/usr/bin/env ruby

require_relative &amp;#39;sprite_generator&amp;#39;

THEMES = [&amp;#39;uk&amp;#39;, &amp;#39;default&amp;#39;]

THEMES.each{|t| SpriteGenerator.generate t }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;sprite_generator.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;fileutils&amp;#39;

class SpriteGenerator
  def self.generate(theme)
    new(theme).generate
  end

  def initialize(theme)
    @theme = theme
  end

  def generate
    create_sprite
    compute_size_and_offset
    FileUtils.rm_rf css_output_path
    FileUtils.mkdir_p css_output_path
    generate_css
  end

  private

  def create_sprite
    FileUtils.rm_rf output_path
    FileUtils.mkdir_p output_path
    `convert -background transparent -append #{theme_path}/*.png #{output_path}/#{sprite_filename}`
  end

  def theme_path
    @theme_path ||= &amp;quot;front-end/resources/images/#{@theme}/theme&amp;quot;
  end

  def output_path
    @output_path ||= &amp;quot;public/assets/#{@theme}&amp;quot;
  end

  def sprite_filename
    @sprite_filename ||= &amp;quot;theme-#{checksum}.png&amp;quot;
  end

  def checksum
    @checksum ||= `cat #{theme_path}/*.png|md5sum`.match(/(.*?)\s/)[1]
  end

  def compute_size_and_offset
    dimensions = `identify -format &amp;quot;%wx%h,%t\\n&amp;quot; #{theme_path}/*.png`
    @image_props = []
    offset = 0
    dimensions.split(&amp;quot;\n&amp;quot;).each do |d|
      m = d.match /(\d+)x(\d+),(.*)/
      w, h, name = m[1..-1]
      @image_props &amp;lt;&amp;lt; (prop = [w.to_i, h = h.to_i, name, offset])
      @sort_ascending = prop if name == &amp;#39;sort-ascending&amp;#39; # special behavior
      @sort_desc = prop if name == &amp;#39;sort-descending&amp;#39; # special behavior
      offset += h
    end
  end

  def css_output_path
    @css_output_path ||= &amp;quot;app/assets/stylesheets/themes/#{@theme}&amp;quot;
  end

  def generate_css
    sp = @sort_ascending
    common_rules = [
      @image_props.map{|(w, h, name, offset)| &amp;quot;.theme-#{name}&amp;quot;}.join(&amp;#39;, &amp;#39;),
      &amp;#39;, a.sort.ascending:after, a.sort.descending:after {&amp;#39;,
      &amp;quot;  background-image: url(/assets/#{@theme}/#{sprite_filename});&amp;quot;,
      &amp;#39;  background-repeat: no-repeat;&amp;#39;,
      &amp;#39;  display: inline-block;&amp;#39;,
      &amp;#39;  border: 0;&amp;#39;,
      &amp;#39;  background-color: transparent;&amp;#39;,
      &amp;#39;}&amp;#39;,
      @image_props.map{|(w, h, name, offset)| &amp;quot;button.theme-#{name}&amp;quot;}.join(&amp;#39;, &amp;#39;),
      &amp;#39;{&amp;#39;,
      &amp;quot;  cursor: pointer;&amp;quot;,
      &amp;#39;  outline: none;&amp;#39;,
      &amp;#39;}&amp;#39;,
      @image_props.map{|(w, h, name, offset)| &amp;quot;.theme-#{name}.disabled&amp;quot;}.join(&amp;#39;, &amp;#39;),
      &amp;#39;{&amp;#39;,
      &amp;quot;  -webkit-filter: grayscale(100%);&amp;quot;,
      &amp;#39;  filter: grayscale(100%);&amp;#39;,
      &amp;#39;}&amp;#39;,
    ].join &amp;quot;\n&amp;quot;
    content = @image_props.map do |(w, h, name, offset)|
      [
        &amp;quot;.theme-#{name} {&amp;quot;,
        &amp;quot;  height: #{h}px;&amp;quot;,
        &amp;quot;  width: #{w}px;&amp;quot;,
        &amp;quot;  background-position: 0 -#{offset}px;&amp;quot;,
        &amp;quot;}&amp;quot;,
      ].join &amp;quot;\n&amp;quot;
    end.join(&amp;quot;\n&amp;quot;)
    File.write &amp;quot;#{css_output_path}/theme.css&amp;quot;, &amp;quot;#{common_rules}\n\n#{content}&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Final notes&lt;/h2&gt;
&lt;p&gt;You can find some numbers on how this set up improved the loading time of our application
in the &lt;a href=&quot;/en/articles/2016-02-29-getting-an-spa-to-load-the-fastest-possible-way-and-how-webpack-can-help-you#some-numbers&quot;&gt;generic webpack article &amp;quot;Some numbers&amp;quot; section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even though it may require a lot of effort to migrate from Sprockets to Webpack, there are tons
of advantages of doing so, including performance improvements for loading your application faster
and additional features support, like source-maps, much easier integration with NPM and bower
packages, support for more compilers/transpilers and ability to move your front-end code to a
separate project. And it&amp;#39;s also a much more easily customizable solution, allowing you to easily
change the build configuration by using regular JavaScript in the Node.js environment.&lt;/p&gt;
&lt;p&gt;If you want to take your loading time performance to the next level, then I&amp;#39;d say moving out from
Sprockets is a must and webpack is the only solution I was able to find in my research that will
allow you to do that.&lt;/p&gt;
</content:encoded></item><item><title>Preventing NewRelic RUM metrics for certain clients with Rails apps</title><link>https://rosenfeld.page/articles/ruby-rails/2014_05_16_preventing_newrelic_rum_metrics_for_certain_clients_with_rails_apps/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2014_05_16_preventing_newrelic_rum_metrics_for_certain_clients_with_rails_apps/</guid><pubDate>Fri, 16 May 2014 15:56:00 GMT</pubDate><content:encoded>&lt;p&gt;We use the awesome &lt;a href=&quot;http://sensuapp.org/&quot;&gt;Sensu&lt;/a&gt; monitoring framework to make sure
our application works as expected. Some of our checks use a headless browser
(&lt;a href=&quot;http://phantomjs.org/&quot;&gt;PhantomJS&lt;/a&gt;) to explore parts of the application, like
exporting search results to Excel or making sure no error is thrown from JS in our
Single Page Application. We also use NewRelic and Pingdom to get some other metrics.&lt;/p&gt;
&lt;p&gt;But since PhantomJS acts like a real browser, our checks will have influence over
the RUM metrics we get from NewRelic, but we&amp;#39;re not really interested in such
metrics. We want the metrics from real users, not our monitoring system.&lt;/p&gt;
&lt;p&gt;My initial plan was to check if I could filter some IP&amp;#39;s from RUM metrics and asked
NewRelic support about this possibility, for which they said it&amp;#39;s not supported yet,
unless you want to &lt;a href=&quot;https://docs.newrelic.com/docs/ruby/blocking-controller-instrumentation&quot;&gt;filter specific controllers or actions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since some monitoring scripts have to go through real actions, this was not an option for us.
So I decided to take a look at the newrelic_rpm gem and could come with a solution that
I&amp;#39;ve confirmed is working fine for us.&lt;/p&gt;
&lt;p&gt;Since we have a single page application, I simply add the before-action filter to the main
action, but you may adapt it to use in your ApplicationController if you will. This is what
I did:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class MainController &amp;lt; ApplicationController
  before_action :ignore_monitoring, only: :index if defined? ::NewRelic

  def index
    # ...
  end

  private

  def ignore_monitoring
    return unless params[:monitoring]
    ::NewRelic::Agent::TransactionState.tl_get.current_transaction.ignore_enduser!
  rescue =&amp;gt; e
    logger.error &amp;quot;Error in ignore_monitoring filter: #{e.message}\n#{e.backtrace.join &amp;quot;\n&amp;quot;}&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rescue clause is there in case the implementation of newrelic_rpm changes and we
don&amp;#39;t notice it. We decided to send a &amp;quot;monitoring=true&amp;quot; param to our requests performed by
our monitoring scripts. This way we don&amp;#39;t have to worry about managing and updating a
list of monitoring servers and figure out how to update that list in our application
without incurring in any down-time.&lt;/p&gt;
&lt;p&gt;But in case you want to deal with this somehow, you might be interested in testing
&amp;quot;request.remote_ip&amp;quot; or &amp;quot;request.env[&amp;#39;&lt;a href=&quot;http://en.wikipedia.org/wiki/X-Forwarded-For&quot;&gt;HTTP_X_FORWARDED_FOR&lt;/a&gt;&amp;#39;]&amp;quot;.
Just make sure you add something like this to your nginx config file (or a similar trick
for your proxy server if you&amp;#39;re using one):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;location ... {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Sequel is awesome and much better than ActiveRecord</title><link>https://rosenfeld.page/articles/ruby-rails/2013_12_18_sequel_is_awesome_and_much_better_than_activerecord/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2013_12_18_sequel_is_awesome_and_much_better_than_activerecord/</guid><pubDate>Wed, 18 Dec 2013 22:40:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#39;ve been using Sequel in production since 2012, April and I still think this is the best
decision I&amp;#39;ve made so far for the whole project lifetime.&lt;/p&gt;
&lt;p&gt;I had played with it sometimes in the past years, when Arel hasn&amp;#39;t been added to ActiveRecord
yet and I found it amazing on how it supported lazy queries. Then I spent a few years working
with Java, Groovy and Grails when I changed my job in 2009, but kept reading about Ruby
(and Rails) news until I found out that AR has added support for lazy queries through Arel,
when Rails 3 was released. Then I assumed AR would be a better fit than Sequel since it&amp;#39;s already
integrated with Rails and lots of great plug-ins would support it better.&lt;/p&gt;
&lt;p&gt;I was plain wrong! In 2011 I changed my job again to work on another Grails application. After
finding a bug with no fix or workaround available I decided to create a Rails application to
forward the affected requests to. So, in April of 2012 I started to create my Rails app and
its models using ActiveRecord. A week later I moved all models from ActiveRecord to Sequel
and have been happy since then.&lt;/p&gt;
&lt;p&gt;Writing some queries with ActiveRecord was still a pain while Sequel made it was a joy to work
with. The following sections will go to each topic I find Sequel is an improvement over AR.&lt;/p&gt;
&lt;h2&gt;Database pooling implementation&lt;/h2&gt;
&lt;p&gt;These days I decided to recreate a few models with ActiveRecord so that we could use an admin
interface with the &lt;code&gt;activeadmin&lt;/code&gt; gem, since it doesn&amp;#39;t support Sequel. After a few requests
to the admin interface it stopped responding with timeout errors.&lt;/p&gt;
&lt;p&gt;Then I decided to write some code to test my suspicions and run it in the console:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;pool_size = ActiveRecord::Base.connection_pool.size
(pool_size + 1).times{ Thread.start{AR::Field.count}.join }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This yielded an timeout error in the last run. This didn&amp;#39;t happen with my Sequel models:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;pool_size = Sequel::Model.db.pool.size
(pool_size + 1).times.map{ Thread.start{Field.count} }.each &amp;amp;:join
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that I don&amp;#39;t even need the &lt;code&gt;join&lt;/code&gt; call inside the block for it to work since the &lt;code&gt;count&lt;/code&gt;
call is so much faster than the &lt;code&gt;timeout&lt;/code&gt; settings.&lt;/p&gt;
&lt;p&gt;The curious thing is that I didn&amp;#39;t get any timeout errors when using &lt;code&gt;activeadmin&lt;/code&gt; with a regular
Rails application, so I investigated what was so special on it that I could access the admin
interface as many time I wanted and it wouldn&amp;#39;t ever timeout.&lt;/p&gt;
&lt;p&gt;I knew the main difference between my application and a regular Rails application is that
I only required &lt;code&gt;active_record&lt;/code&gt;, while Rails will require &lt;code&gt;active_record/railtie&lt;/code&gt;. So I decided
to take a look at its content and found this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;config.app_middleware.insert_after &amp;quot;::ActionDispatch::Callbacks&amp;quot;,
  &amp;quot;ActiveRecord::ConnectionAdapters::ConnectionManagement&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I found that AR was tricking here delegating the pool management to the web layer by always
clearing active connections from the pool after the request was processed in that middle-ware:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;ActiveRecord::Base.clear_active_connections! unless testing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Despite the name &lt;em&gt;clear_active_connections!&lt;/em&gt; it seems to actually only close and checkin
back to the pool the single current connection, whose id is stored in a thread local variable,
from my understanding after taking a glance over AR pool management source code. That means that
if the request main thread spawns a new thread any connection checked out in the new thread won&amp;#39;t
be automatically collected by Rails and your application would start to throw timeout exceptions
when waiting for a connection to be available in the pool, for no obvious reason, unless you
understand how the connection pool works in AR and how it&amp;#39;s integrated in Rails. Here&amp;#39;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class MainController
  def index
    Thread.start{ Post.count }
    head :ok
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try running this controller using a single server process 6 times (assuming the pool size is
the default of 5 connections). This should fail:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;ab -n 6 -c 1 http://localhost:3000/main/index
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That means the user is responsible for closing the connection, checking it in back to the pool
before the thread is terminated. This wouldn&amp;#39;t be a concern if Post was a Sequel model.&lt;/p&gt;
&lt;p&gt;Then I recalled &lt;a href=&quot;http://tenderlovemaking.com/2011/10/20/connection-management-in-activerecord.html&quot;&gt;this article from Aaron Patterson&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update note:&lt;/strong&gt; it seems this specific case will be fixed in ActiveRecord 4.2 due to 
the automatic connection check-in upon dead threads strategy implemented in 
&lt;a href=&quot;https://github.com/rails/rails/pull/14360/files&quot;&gt;pull request #14360&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Ability to join the same table multiple times with different aliases&lt;/h2&gt;
&lt;p&gt;The main reason I left AR for Sequel was the need for joining the same table multiple times
with different aliases for each joined table. Take a look at this snippet from this
&lt;a href=&quot;https://github.com/rosenfeld/sequel-ar-example&quot;&gt;sample project&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;module Sq
  class Template &amp;lt; Sequel::Model
    one_to_many :fields

    def mapped_template_ids
      FieldMapping.as(:m).
        join(Field.named(:f), id: :field_id, template_id: id).
        join(Field.named(:mf), id: :m__mapped_field_id).
        distinct.select_map(:mf__template_id)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I still don&amp;#39;t know how to write such query using AR. If you do, please comment on how to do so
without resorting to plain SQL or Arel, which is considered an internal implementation detail
of AR for which the API could change anytime even for a patch release.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;as&lt;/code&gt; and &lt;code&gt;named&lt;/code&gt; are not part of Sequel::Model, but implemented as a plug-in. See next section.&lt;/p&gt;
&lt;h2&gt;Built-in plugin support for models&lt;/h2&gt;
&lt;p&gt;Although it&amp;#39;s not a strong reason to move to Sequel, since it&amp;#39;s easily implemented with
regular Ruby modules in AR, it&amp;#39;s nice to have such a built-in API for extending models:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;module Sequel::Plugins::AliasSupport
  module ClassMethods
    def as(alias_name)
      from named alias_name
    end

    def named(alias_name)
      Sequel.as table_name, alias_name
    end
  end
end
Sequel::Model.plugin :alias_support
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Support for composite primary keys&lt;/h2&gt;
&lt;p&gt;Sequel does support composite primary keys, which are specially useful for join tables, while
ActiveRecord requires a unique column as the primary key.&lt;/p&gt;
&lt;h2&gt;No need to monkey patch it&lt;/h2&gt;
&lt;p&gt;It seems lots of people don&amp;#39;t find AR&amp;#39;s API good enough because they keep monkey patching it
all the time. I really try very hard to avoid any dependency on a library that relies on monkey
patching something, specially AR, since it&amp;#39;s always changing its internal implementation.&lt;/p&gt;
&lt;p&gt;So, with all major and minor Rails release we often find gems that stopped working due to such
internal changes. For example, &lt;code&gt;activeadmin&lt;/code&gt; stopped working with Rails 4.1.0.beta1 release
even if the public AR public API remained the same.&lt;/p&gt;
&lt;p&gt;It takes so much time to work on code that relies on monkey patching AR, that Ernie Miller,
after several years trying to provide improvements over AR
&lt;a href=&quot;http://erniemiller.org/2013/11/17/anyone-interested-in-activerecord-hackery/&quot;&gt;gave up&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Not surprisingly, one of the gems he used to maintain, &lt;code&gt;polyamorous&lt;/code&gt;, was the reason why
&lt;code&gt;activeadmin&lt;/code&gt; stopped working with latest Rails release.&lt;/p&gt;
&lt;p&gt;I never felt the need for monkey patching Sequel&amp;#39;s classes.&lt;/p&gt;
&lt;h2&gt;Documentation&lt;/h2&gt;
&lt;p&gt;Sequel&amp;#39;s documentation is awesome! That was the first thing I noticed when I moved from AR to
Sequel. Arel is considered internal implementation detail and AR users are not supposed to rely
on Arel&amp;#39;s API, which makes AR&amp;#39;s API much more limited besides being badly documented.&lt;/p&gt;
&lt;h2&gt;Support&lt;/h2&gt;
&lt;p&gt;Sequel&amp;#39;s mailing list has awesome support from Jeremy Evans, the gem maintainer. As for AR,
there&amp;#39;s no dedicated list for it and one has to subscribe to a Rails related list to discuss
AR stuff.&lt;/p&gt;
&lt;h2&gt;Separation of concerns&lt;/h2&gt;
&lt;p&gt;I like to keep the concerns separately and I can&amp;#39;t think about why an ORM solution should be
attached to a web framework implementation. If Rails has great features in a new release with
regards to action handling, I shouldn&amp;#39;t be forced to upgrade the ORM library at the same time
I upgrade Rails.&lt;/p&gt;
&lt;p&gt;Also, if a security fix affects AR only, why should a new Rails version be released?&lt;/p&gt;
&lt;p&gt;Often AR will introduce incompatibilities in new versions, while I haven&amp;#39;t seen this happening
with Sequel yet for the features I use. Also, I&amp;#39;m free to upgrade either Rails or Sequel any time.&lt;/p&gt;
&lt;p&gt;Of course, this doesn&amp;#39;t apply to ORM solutions only, but it&amp;#39;s also valid for mailing handling
but this is another topic, so I&amp;#39;ll focus on Sequel vs AR comparison only.&lt;/p&gt;
&lt;h2&gt;Sequel can also be useful without models&lt;/h2&gt;
&lt;p&gt;Sometimes it doesn&amp;#39;t make sense to create a model for each table. Sequel&amp;#39;s database object allows
you to easily access any table directly while still supporting all dataset methods like you&amp;#39;d do
with Sequel models:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;  DB = Sequel::Model.db # or Sequel.connect &amp;#39;postgres://localhost/my_database&amp;#39;
  mapped_template_ids = DB[:field_mappings___m]
      join(:fields___f, id: :m__field_id, template_id: 1).
      join(:fields___mf, id: :m__mapped_field_id).
      where(f__deleted: false, mf__deleted: false).
      distinct.select_map(:mf__template_id)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Philosophy&lt;/h2&gt;
&lt;p&gt;AR&amp;#39;s philosophy is to delegate constraints to the application model&amp;#39;s layer, while Sequel prefers
to implement all constraints in the database level, when possible/viable. I&amp;#39;ve always agreed that
we should enforce all constraints in the database level. But this isn&amp;#39;t common among most AR
users. AR migrations doesn&amp;#39;t make it easier to create a foreign key properly using its DSL,
for example and treat them as second-class citizen, as opposed to Sequel&amp;#39;s philosophy.&lt;/p&gt;
&lt;p&gt;The only RDBMS database solution I currently use is PostgreSQL and I really want to use several
features that are only supported by PostgreSQL. Sequel&amp;#39;s PG adapter allows me to use those
features if I want to, even knowing that it won&amp;#39;t work for other database vendors.&lt;/p&gt;
&lt;p&gt;This includes recursive transactions through save-points, options to drop temp table on commit
and so on.&lt;/p&gt;
&lt;p&gt;Another example: AR 4.1.0.beta1 introduced support for enums, in a database independent way.&lt;/p&gt;
&lt;p&gt;I&amp;#39;d much prefer to use PostgreSQL&amp;#39;s enum type for things like that, which comes with
database-side built-in validations/constraints.&lt;/p&gt;
&lt;p&gt;Also, although you can manage association cascades in the application-side using
&lt;a href=&quot;http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/AssociationDependencies.html&quot;&gt;this plugin&lt;/a&gt; with Sequel, usually you&amp;#39;d be advised to perform such cascade operations in the
database level when creating the foreign keys, for instance. Also, when a database trigger
better takes care of an after/before hook than an application&amp;#39;s code, you should not be afraid
of getting advantage of those.&lt;/p&gt;
&lt;h2&gt;Faster testing when using factories&lt;/h2&gt;
&lt;p&gt;With PostgreSQL feature of using save-points in transactions, I can set-up RSpec to allow
transactional &lt;code&gt;before/after(:all)&lt;/code&gt; blocks in addition to the &lt;code&gt;before/after(:each)&lt;/code&gt; ones.&lt;/p&gt;
&lt;p&gt;This allows me to save quite some time when I can create several database records in a context
which will then be shared among several examples, instead of recreating them every-time.&lt;/p&gt;
&lt;p&gt;RSpec&amp;#39;s support for this is not good (like having a &lt;code&gt;let&lt;/code&gt; global variant over the context) but
it&amp;#39;s not hard to get this set-up working in a good enough way, speeding up my test suite a lot.&lt;/p&gt;
&lt;p&gt;And it&amp;#39;s pretty easy to use Sequel&amp;#39;s core support for nested transactions so that I can be sure
that the database state will be always consistent before each example is run.&lt;/p&gt;
&lt;h2&gt;Migrations&lt;/h2&gt;
&lt;p&gt;I strongly believe a database&amp;#39;s schema change should be handled by a separate project, instead
of inside an application using the database. More applications may use the same database at some
point and it makes sense that managing your database should be handled by a separate application.&lt;/p&gt;
&lt;p&gt;I still don&amp;#39;t have a favorite migrations solutions as each of them have their pros and drawbacks.
I&amp;#39;m still using AR&amp;#39;s migration for historical reasons, as I used the &lt;code&gt;standalone_migrations&lt;/code&gt; gem
in a separate project even when my application was written only in Grails and the Rails app didn&amp;#39;t
exist yet. Since &lt;code&gt;standalone_migrations&lt;/code&gt; only supports AR 3.x branch, and I was interested in some
features from AR 4, I created another gem, called
&lt;a href=&quot;https://github.com/rosenfeld/active_record_migrations&quot;&gt;&lt;code&gt;active_record_migrations&lt;/code&gt;&lt;/a&gt; to be able to
use AR 4 migrations support in stand-alone mode.&lt;/p&gt;
&lt;h3&gt;DSL&lt;/h3&gt;
&lt;p&gt;I much prefer the Sequel&amp;#39;s DSL for writing the migrations as it supports more things in an easier
way than AR&amp;#39;S migrations. Also, I&amp;#39;m allowed to use any dataset methods from an migration, instead
of having to write everything not supported by the DSL as plain SQL queries.&lt;/p&gt;
&lt;p&gt;On the other side, AR, since version 4, allows us to have an &lt;code&gt;reversible&lt;/code&gt; block inside a &lt;code&gt;change&lt;/code&gt;
method which can be quite useful.&lt;/p&gt;
&lt;h3&gt;Tooling&lt;/h3&gt;
&lt;p&gt;AR provides a good migration generator, which lacks on Sequel and can be very helpful when
creating new migrations.&lt;/p&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;I didn&amp;#39;t create any specific performance tests to compare both ORM solutions but I do remember
that my specs run much faster when I migrated from AR to Sequel and I&amp;#39;ve also heard from other
people that Sequel is faster for most use cases, in MRI at least.&lt;/p&gt;
&lt;h2&gt;Query DSL&lt;/h2&gt;
&lt;p&gt;I really like to have control over the generated SQL and a good ORM solution for me is one that
will allow me to have better control over it. That&amp;#39;s why I don&amp;#39;t like the Hibernate&amp;#39;s HQL language.&lt;/p&gt;
&lt;p&gt;The database should be your friend and if it supports some functions or syntax that would help you
why not use them?&lt;/p&gt;
&lt;p&gt;Sequel allows me to use nearly all features available through its DSL from my database vendor
of choice: PostgreSQL. It also provides me easy access and documentation to use all kind of
stuff I can do with plain SQL like &amp;quot;ilike&amp;quot; expressions, sub-queries, nested transactions,
import data from file, recursive queries, Common Table Expressions (WITH queries) and so on.&lt;/p&gt;
&lt;h2&gt;Why not using straight SQL instead of some ORM when cross-database vendors is not an issue?&lt;/h2&gt;
&lt;p&gt;First, I&amp;#39;d like to say that most of Sequel DSL actually supports multiple database vendors.&lt;/p&gt;
&lt;p&gt;But I only find that useful if you&amp;#39;re writing some kind of plug-in or library that should not
depend on a single database vendor. But that&amp;#39;s not the case for general use applications.&lt;/p&gt;
&lt;p&gt;Once you opt for some database vendor in your application, you shouldn&amp;#39;t have to worry about
supporting other database vendors.&lt;/p&gt;
&lt;p&gt;So, someone might ask why using any ORM solution if you&amp;#39;re fine with writing plain SQL?&lt;/p&gt;
&lt;p&gt;There are many reasons for that. First, most plug-ins expect some Ruby interface to deal with,
instead of SQL. This is the case with FactoryGirl, Devise and so on. But this is not the main
reason.&lt;/p&gt;
&lt;p&gt;An ORM provides lots of goodies, like an easy-to-use API to create and update records, automatic
typecasting, creating transactions and much more. But even this is not the main reason for me
to prefer an ORM over plain SQL.&lt;/p&gt;
&lt;p&gt;The main reason for me is the ability to easily compose a query in some way that is easy to
read and maintain, specially when parts of the query depend on the user requesting it or some
controller&amp;#39;s param. It&amp;#39;s great that you can change some query on the fly, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;  fields_dataset = Field.where(template_id: params[:id])
  fields_dataset = fields_dataset.exclude(invisible: true) unless current_user.admin?
  # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Sequel&amp;#39;s drawbacks&lt;/h2&gt;
&lt;p&gt;When a generic query is performed, Sequel will convert any returned rows as hashes with the
column names as keys converted to symbols. This may be a problem if you generate the queries
dynamically and alias them based on some table&amp;#39;s id that depend on the user input. If you have
enough ids being queried, Sequel may create lots of symbols that will never be garbage collected.&lt;/p&gt;
&lt;p&gt;The lack of migration generators built-in for Sequel migrations makes the creation of new
migrations a less than ideal task. You may create some custom rake task to aid with migration
creations and it shouldn&amp;#39;t be complicated but having that support built into the Sequel core
would certainly help.&lt;/p&gt;
&lt;p&gt;The main drawback of Sequel is certainly lack of native support of other great gems like Devise,
ActiveAdmin and Rails itself. Quite some useful Rails plug-ins will only integrate with
ActiveRecord.&lt;/p&gt;
&lt;h2&gt;Overall feeling&lt;/h2&gt;
&lt;p&gt;Most of my server-side tasks involve querying data from an RDMBS database and serving JSON
representations to the client-side API. So, an ORM solution is a key library for me.&lt;/p&gt;
&lt;p&gt;And I couldn&amp;#39;t be happier with all goodness I get from Sequel, which gets out of my way when
querying the database in contrast with ActiveRecord, when I used to spend a lot of time trying
to figure out whether some kind of query was possible at all.&lt;/p&gt;
&lt;p&gt;Thanks, Jeremy Evans, for maintaining such a great library and being so responsive in the
mailing list! I really appreciate your efforts, documentation and Sequel itself.&lt;/p&gt;
&lt;p&gt;Also, thank you for kindly reviewing this article, providing insightful improvements over it.&lt;/p&gt;
&lt;p&gt;Finally, if you&amp;#39;re interested on getting started with Sequel in a Rails application, I&amp;#39;ve
published &lt;a href=&quot;/en/articles/2012-04-18-getting-started-with-sequel-in-rails&quot;&gt;another article&lt;/a&gt;
on the subject on April, 2012.&lt;/p&gt;
</content:encoded></item><item><title>Server-side or Client-side focus?</title><link>https://rosenfeld.page/articles/2013_12_11_server_side_or_client_side_focus/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2013_12_11_server_side_or_client_side_focus/</guid><pubDate>Wed, 11 Dec 2013 10:56:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://37signals.com/svn/writers/dhh&quot;&gt;David&lt;/a&gt; wrote a great
&lt;a href=&quot;http://37signals.com/svn/posts/3697-server-generated-javascript-responses&quot;&gt;article&lt;/a&gt; on the
subject, suggesting that keeping all views generated in the server-side is the way to go for
most applications.&lt;/p&gt;
&lt;p&gt;If you haven&amp;#39;t read it yet, please do so, as this article was written to approach a few topics
that I think are missing in that article.&lt;/p&gt;
&lt;p&gt;Web applications can be written in many ways. In the early days JavaScript played a marginal role
in web applications, performing some simple form validations and the like but currently more
and more applications are making heavy use of JavaScript and lots of them are built as Single
Page Applications (SPA).&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been working on SPA&amp;#39;s since 2009, while David&amp;#39;s applications are mostly built around the
original concept of web applications, by delegating as much as possible to the server-side.&lt;/p&gt;
&lt;p&gt;Both approaches are valid ones, but as the complexity of dynamic browser behavior increases,
I do believe that moving the UI to the client-side is usually better than generating them in
the server.&lt;/p&gt;
&lt;p&gt;So, if that&amp;#39;s the case for your application, please keep reading.&lt;/p&gt;
&lt;h2&gt;Server-side template and JavaScript generation&lt;/h2&gt;
&lt;p&gt;In David&amp;#39;s article, he refers to this approach as Server-generated JavaScript Responses (SJR),
even if most of the response is actually HTML, not JavaScript, but I&amp;#39;ll keep his SJR terminology
in this article to make it easier for me to refer to it.&lt;/p&gt;
&lt;p&gt;Here are some spotted advantages:&lt;/p&gt;
&lt;h3&gt;Sharing templates between server-side and client-side&lt;/h3&gt;
&lt;p&gt;By rendering some HTML and JS in the server-side, one may reuse partial templates.&lt;/p&gt;
&lt;p&gt;This is indeed a valid argument, but it doesn&amp;#39;t apply if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All your views are generated in the client-side; (which he mentioned in the article)&lt;/li&gt;
&lt;li&gt;You use some template language that can be shared both in the server-side and
client-side instead of ERB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Less computational power needed on the client&lt;/h3&gt;
&lt;p&gt;On the other hand devices are becoming faster and faster and it&amp;#39;s cheaper to move the processing
to the client-side when scaling your infrastructure. In the long-term I don&amp;#39;t think it worths
insisting on server-side processing because of this reason.&lt;/p&gt;
&lt;p&gt;Some time ago I was trying to reduce the load time for our application and I implemented
server-side generation of a big table in Rails and cached it in the server. It was obvious to me
that it would save me almost 200ms (the time it was taking me to render that same template
in the client-side - it should save even more for slower browsers/computers/devices).&lt;/p&gt;
&lt;p&gt;The previous approach was to embed the JSON (also cached in the server-side) in the HTML
(to avoid another request/latency) and render the template in the client-side. I was
surprised that the page actually took a bit longer to load after the change. Sorry, I can&amp;#39;t
explain the reason, but I gave up on the idea. And yes, I have always been served gzipped content
(both HTML, assets and JSON).&lt;/p&gt;
&lt;h3&gt;It&amp;#39;s supposed to be faster&lt;/h3&gt;
&lt;p&gt;But it will actually depend on lots of things. For example, if some of the templates don&amp;#39;t need
server-side data to be rendered, the network latency will be enough to make the server-side
approach for rendering the template slower.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re appending a template that never changes you could cache it in the client-side and avoid
the round trip to the server every time you need the template, but if it depends on other data
that you already have available in the client-side, the server-side template rendering approach
won&amp;#39;t be faster.&lt;/p&gt;
&lt;p&gt;Also, if you have to deal with several data state that is not stored in the database, trying to
keep (or pass) all that state to the server-side will lead to insane maintenance.&lt;/p&gt;
&lt;h3&gt;Views can be cached&lt;/h3&gt;
&lt;p&gt;But this is valid for JSON as well, which David didn&amp;#39;t mention in his article, so it can&amp;#39;t be
viewed as a benefit of SJR over client-side rendering.&lt;/p&gt;
&lt;p&gt;Also, one can always embed the templates in the generated (minified) application assets and they
will be cached naturally by your browsers for all later requests. So, if the template generates
lots of HTML, it will be certainly much faster to transfer only the data instead of the full
template even when serving the template using gzipped content. The reason why David claims it
doesn&amp;#39;t make much difference is probably because his generated HTML are small enough.&lt;/p&gt;
&lt;h3&gt;Easy-to-follow execution flow&lt;/h3&gt;
&lt;p&gt;This is really a matter of taste and I find it much easier to debug the template generation in
Chrome Developer&amp;#39;s Tool and to follow the flow in the client-side code, so I won&amp;#39;t comment on this.&lt;/p&gt;
&lt;p&gt;Also, it seems that the author suggests that a major benefit of this &amp;quot;simplified&amp;quot; flow, is that
you don&amp;#39;t have to worry about testing it because it just uses a standard mechanism that&amp;#39;s already
tested as part of the framework and that couldn&amp;#39;t go wrong. Which leads me to:&lt;/p&gt;
&lt;h3&gt;Faster initial rendering&lt;/h3&gt;
&lt;p&gt;This is indeed a very valid point. Once you serve your HTML the browser will already display it
before running all JS code which improves the page load time perception from the application
user point of view.&lt;/p&gt;
&lt;p&gt;On the other hand, if the user is too fast on clicking on some element with attached behavior
(although not yet in the very beginning of the page load), the user experience may not be very
good and the user might perceive that lack of behavior as an application bug.&lt;/p&gt;
&lt;p&gt;Also, with Rails, if the server-side page takes quite some time to be rendered, by default the
browser won&amp;#39;t show anything until the render action finishes because Rails doesn&amp;#39;t render
streamed responses by default.&lt;/p&gt;
&lt;p&gt;On the other hand, if you send a minimal page, you&amp;#39;re able to inform the user that the page is
loading very quickly, while you wait for a JSON response with the actual data, for instance.&lt;/p&gt;
&lt;p&gt;It means that depending on how you design your site, the user might have a better experience
with the asynchronous approach, but that indeed is not trivial to implement in a good way.&lt;/p&gt;
&lt;p&gt;In our application we use the jQuery-layout plugin to render our panes otherwise the
application would look badly so it doesn&amp;#39;t help if we start rendering some HTML soon...&lt;/p&gt;
&lt;p&gt;So this is very application-specific.&lt;/p&gt;
&lt;h2&gt;The main reason I believe client-side template rendering is more interesting: Testing&lt;/h2&gt;
&lt;p&gt;When building SPA&amp;#39;s, lots of your code remain in the client-side, and tools you use to test
server-side code, like RSpec and the like, are no longer well suited for testing browser behavior.&lt;/p&gt;
&lt;p&gt;Trying to test all your client-side logic as Capybara tests are simply too slow to be a valid
approach.&lt;/p&gt;
&lt;p&gt;On the other side, testing in the browser is super fast. Much faster than testing the server-side
code usually. You may simply mock all your requests to the server-side and test both parts of
your application quickly in isolation from each other.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve written &lt;a href=&quot;https://github.com/rosenfeld/rails-sandbox-assets&quot;&gt;rails-sandbox-assets&lt;/a&gt; a while ago
to allow you to serve all your Rails assets in an easy way and used it as a base for running
lots of runners, like &lt;a href=&quot;https://github.com/rosenfeld/rails_sandbox_jasmine&quot;&gt;Jasmine&lt;/a&gt;,
&lt;a href=&quot;https://github.com/rosenfeld/rails-sandbox-busterjs&quot;&gt;Buster.js&lt;/a&gt;,
&lt;a href=&quot;https://github.com/rosenfeld/rails_sandbox_mocha_chai&quot;&gt;Mocha/Chai&lt;/a&gt; and my own
&lt;a href=&quot;https://github.com/rosenfeld/oojspec&quot;&gt;oojspec&lt;/a&gt;. They can even live together.&lt;/p&gt;
&lt;p&gt;This way, if all my views are generated in the client-side, it&amp;#39;s pretty easy to recreate my
client-side application from the specs without using any HTML fixtures, by simply requiring
my client-side code using the Rails Asset Pipeline in my specs and running them after mocking
jQuery.ajax to return data the way Rails would do.&lt;/p&gt;
&lt;p&gt;Before David wrote that article, we discussed about this topic by e-mail and in my last e-mail
I suggested him to talk about how they test their code using this approach. Since he didn&amp;#39;t
follow my suggestion (although he followed other suggestions, like coming with a new and 
less confusing name than RJS) I&amp;#39;m assuming he doesn&amp;#39;t actually have a good response yet to how
to test this and I&amp;#39;m assuming they don&amp;#39;t have enough client-side code to worry about this.&lt;/p&gt;
&lt;p&gt;But if someone is considering his suggestion of using the SJR approach and has lots of behavior
in the client-side, please take some time to think on how you&amp;#39;re gonna handle testing using
that route.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By no means the intent of this article is to tell you that you shouldn&amp;#39;t write your application
using SJR. It can be indeed a valid approach depending on how you&amp;#39;re designing your application.&lt;/p&gt;
&lt;p&gt;The specific design I would recommend against SJR, is for SPA&amp;#39;s, as I&amp;#39;m writing solely those
kind of application since 2009 and I can&amp;#39;t think of SJR being used with great benefit in such
applications.&lt;/p&gt;
</content:encoded></item><item><title>Running Java from MRI Ruby through DRb</title><link>https://rosenfeld.page/articles/ruby-rails/2013_07_16_running_java_from_mri_ruby_through_drb/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2013_07_16_running_java_from_mri_ruby_through_drb/</guid><pubDate>Tue, 16 Jul 2013 11:17:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Important update&lt;/em&gt;: After I wrote this article I tried to put it to work in my real application
and noticed that it can&amp;#39;t really work the way I described due to issues with objects referenced
only in the DRb client side being garbage collected in the DRb server side since no references
are kept for them in the server-side. I&amp;#39;m keeping this article anyway to explain the idea in the
hope we could find a way to work around the memory management issue at some point.&lt;/p&gt;
&lt;h1&gt;Motivation&lt;/h1&gt;
&lt;p&gt;In a Ruby application I maintain, we have the requirement of exporting some statistics to XLS (not XLSX)
and we had to modify a XLS template for doing that.&lt;/p&gt;
&lt;p&gt;After searching the web I couldn&amp;#39;t find a Ruby library that would do the job, but I knew I could count on the
&lt;a href=&quot;http://poi.apache.org/&quot;&gt;Apache POI&lt;/a&gt; java library.&lt;/p&gt;
&lt;p&gt;MRI Ruby doesn&amp;#39;t have native support for using Java libraries so we have to either use JRuby or some
Inter-Process Communication (IPC) approach (I consider hosting a service over HTTP as another form of IPC).&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve already used JRuby for serving my web application in the past and we had some good result, but our
application is currently running fine on MRI Ruby 2. I don&amp;#39;t want to use JRuby for deployment only to enable me
to use Java libraries. Sometimes we&amp;#39;ll re-run some stress tests to test the throughput of our application using
several deployment strategies, including using JRuby instead of MRI, in threaded mode (vs the multi-process and
multi-threaded approaches with MRI), testing several web servers for each Ruby implementation.&lt;/p&gt;
&lt;p&gt;Last time we run our stress tests, Unicorn was a bit faster to serve our pages when compared to using JRuby on
Puma, but that wasn&amp;#39;t the main reason why we chose Unicorn. We had some issues with some connections to
PostgreSQL with JRuby by that time and we didn&amp;#39;t want to investigate it further, specially when we didn&amp;#39;t notice
any advantages in the JRuby deployment for that time.&lt;/p&gt;
&lt;p&gt;Things may have changed today but we don&amp;#39;t plan to run another battery of stress tests in the short-run...
I just wanted to find another way of having access to Java libraries that wouldn&amp;#39;t attach our application to
JRuby in any way. Even when we used to deploy with JRuby, all our code ran in MRI and we used MRI to actually
run the tests and also in development mode since it&amp;#39;s much faster to boot and allow faster testing through some
forking techniques (spork, zeus, etc).&lt;/p&gt;
&lt;p&gt;I didn&amp;#39;t want to add much overhead either, by providing some HTTP service. The overhead is not only in the
payload but also in the development work-flow.&lt;/p&gt;
&lt;p&gt;What I really wanted was just a bridge that would allow me to run Java code from MRI Ruby, since I&amp;#39;m more
comfortable with writing code with Ruby and my tests run faster on MRI rather than JRuby.&lt;/p&gt;
&lt;p&gt;So, the obvious choice (at least for me), was to try DRb.&lt;/p&gt;
&lt;h1&gt;DRb to the rescue&lt;/h1&gt;
&lt;p&gt;Even after deciding for DRb, you may implement the service with multiple approaches. The simplest one is
probably to write the service in JRuby and only access the higher-level interface from the MRI application.&lt;/p&gt;
&lt;p&gt;That works but I wanted to avoid this approach for some reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tests would run slower when compared to MRI due to increased boot time for the JVM (main reason)&lt;/li&gt;
&lt;li&gt;we&amp;#39;d need to switch applications every time we wanted to work on the Java-related code (we don&amp;#39;t use an IDE,
but still, in Vim, that means &amp;#39;:lcd ../jruby-app&amp;#39;)&lt;/li&gt;
&lt;li&gt;Rails already provides us automatic code reloading out-of-the box for our main application, while we&amp;#39;d have to be constantly rebooting the JRuby application after each change or implement some auto-reloading code ourselves&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, I wanted to test another minimal approach that would only allow us to perform any generic JRuby programming
directly from MRI.&lt;/p&gt;
&lt;h1&gt;Dependencies management, Maven and jbundler&lt;/h1&gt;
&lt;p&gt;Note: for this section, I&amp;#39;m assuming JRuby is being used. With RVM that means &amp;quot;rvm jruby&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mkristian&quot;&gt;Christian Meier&lt;/a&gt; did a great job with
&lt;a href=&quot;https://github.com/mkristian/jbundler&quot;&gt;jbundler&lt;/a&gt;, a tool similar to Bundler, that will use a Jarfile instead
of the Gemfile to specify the Maven dependencies.&lt;/p&gt;
&lt;p&gt;So, basically, I created a new Gemfile with &lt;em&gt;bundle init&lt;/em&gt; and added a &lt;em&gt;gem &amp;#39;jbundler&amp;#39;&lt;/em&gt; entry to it.&lt;/p&gt;
&lt;p&gt;Then I created a Jarfile with this content: &lt;em&gt;jar &amp;#39;org.apache.poi:poi&amp;#39;&lt;/em&gt;. Run &lt;em&gt;bundle exec jbundle&lt;/em&gt; and you&amp;#39;re
ready to go. Running &lt;em&gt;jbundle console&lt;/em&gt; will provide an IRB session with the Maven libraries available.&lt;/p&gt;
&lt;p&gt;To create a script, you add a &lt;em&gt;require &amp;#39;jbundler&amp;#39;&lt;/em&gt; statement and you can now run it with
&lt;em&gt;bundle exec ruby script-name.rb&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;The DRb server&lt;/h1&gt;
&lt;p&gt;So, this is how the JRuby server process looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# java_bridge_service.rb:

POI_SERVICE_URL = &amp;quot;druby://localhost:8787&amp;quot;

require &amp;#39;jbundler&amp;#39;
require &amp;#39;drb/drb&amp;#39;
require &amp;#39;ostruct&amp;#39;

class JavaBridgeService
  def run(code, _binding = nil)
    _binding = OpenStruct.new(_binding).instance_eval {binding} if _binding.is_a? Hash
    result = if _binding
      eval code, _binding
    else
      eval code
    end
    result.extend DRb::DRbUndumped if result.respond_to? :java_class # like byte[]
    result
  end

end

puts &amp;quot;listening to #{POI_SERVICE_URL}&amp;quot;
service = DRb.start_service POI_SERVICE_URL, JavaBridgeService.new

Signal.trap(&amp;#39;SIGINT&amp;#39;){ service.stop_service }

DRb.thread.join
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Security note&lt;/h2&gt;
&lt;p&gt;This is all you need to run arbitrary Ruby code from MRI. Since this makes use of &lt;em&gt;eval&lt;/em&gt;, I&amp;#39;d strongly
recommend you use this server in a sandbox environment.&lt;/p&gt;
&lt;h1&gt;The client code&lt;/h1&gt;
&lt;p&gt;I won&amp;#39;t show the full classes we have for communicating with the server since they are implementation details
and people will want to organize it in different ways. Instead I&amp;#39;ll provide some scripting code that you may
want to run in an IRB session to test the set-up:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;
require &amp;#39;drb/drb&amp;#39;

DRb.start_service

service = DRbObject.new_with_uri &amp;#39;druby://localhost:8787&amp;#39;

[
  &amp;#39;java.io.FileInputStream&amp;#39;,
  &amp;#39;java.io.FileOutputStream&amp;#39;,
  &amp;#39;java.io.ByteArrayOutputStream&amp;#39;,
  &amp;#39;org.apache.poi.hssf.usermodel.HSSFWorkbook&amp;#39;,
].each{|java_class| service.run &amp;quot;import #{java_class}&amp;quot;}

workbook = service.run &amp;#39;HSSFWorkbook.new FileInputStream.new(filename)&amp;#39;,
      filename: File.absolute_path(&amp;#39;template.xls&amp;#39;)

sheet = workbook.sheet_at 0
row = sheet.create_row 0
# row.create_cell(0) will display a warning in the server-side since JRuby can&amp;#39;t know if you want to use the
# short or int method signature
cell = service.run &amp;#39;row.java_send :createCell, [Java::int], col&amp;#39;, row: row, col: 0
cell.cell_value = &amp;#39;test&amp;#39;

# export it to binary data
result = service.run &amp;#39;ByteArrayOutputStream.new&amp;#39;
workbook.write result

# ruby_data is what you would be passing to send_data in controllers:
ruby_data = service.run(&amp;#39;ByteArrayInputStream.new baos.to_byte_array&amp;#39;, baos: result).to_io

# or, if you want to export it to some file:
os = service.run &amp;#39;FileOutputStream.new filename&amp;#39;, filename: File.absolute_path(&amp;#39;output.xls&amp;#39;)
workbook.write os
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;By using such a generic Java bridge, we&amp;#39;re able to use several good Java libraries directly from MRI code.&lt;/p&gt;
&lt;h1&gt;Troubleshooting&lt;/h1&gt;
&lt;p&gt;If you&amp;#39;re having any issues with trying that code (I haven&amp;#39;t actually tested the code in this article), please
leave a note in the comments and I&amp;#39;ll fix the article. Also, if you have any questions, create a comment and I&amp;#39;ll
try to help you.&lt;/p&gt;
&lt;p&gt;Or just feel free to thank me if this helped you ;)&lt;/p&gt;
</content:encoded></item><item><title>Rails: the Good and the Bad</title><link>https://rosenfeld.page/articles/ruby-rails/2013_02_16_rails_the_good_and_the_bad/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2013_02_16_rails_the_good_and_the_bad/</guid><pubDate>Sat, 16 Feb 2013 15:41:00 GMT</pubDate><content:encoded>&lt;p&gt;A while ago &lt;a href=&quot;/en/articles/programming/2011-08-07-why-i-prefer-rails-over-grails&quot;&gt;I wrote an article explaining why I don&amp;#39;t like Grails&lt;/a&gt;.
By that time I was doing Grails development daily for almost 2 years. Some statements there are no longer true
and Grails has really improved a lot since 2.0.0. I still don&amp;#39;t like Grails for many more reasons I didn&amp;#39;t find
time (or interest) on writing about.&lt;/p&gt;
&lt;p&gt;Since almost 2 years ago I was back to Rails programming and the application I currently maintain is a mix of
Grails, Rails and Java Spring working together. I feel it is now time to reflect about what I like and what I
don&amp;#39;t in Rails.&lt;/p&gt;
&lt;h2&gt;What kind of web application I&amp;#39;m talking about?&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been working solely on single-page-applications since 2009. All opinions reflected here apply to such kind
of application, although some of them will apply to any web application. This is also what I consider the
current tendency for web applications, like Twitter, Facebook, Google+, GMail and most applications I&amp;#39;ve seen
out there.&lt;/p&gt;
&lt;p&gt;When designing such applications one doesn&amp;#39;t use make heavy use of server-side views (ERB, GSP, JSP, you name)
but usually render your views in the client-side, although some will prefer to render partial content generated
in the server. In the applications I&amp;#39;ve written in those 4 years in different companies and products I&amp;#39;ve been mostly rendering the views in the client-side so also keep that in mind when reading my review.&lt;/p&gt;
&lt;p&gt;Basically I only render a single page in the server-side and have plenty of JavaScript (or CoffeeScript) files that are referenced by this page, usually concatenated in a few JavaScript files for production usage.&lt;/p&gt;
&lt;h2&gt;How does Rails help me on getting my job done?&lt;/h2&gt;
&lt;h3&gt;The Asset Pipeline&lt;/h3&gt;
&lt;p&gt;I&amp;#39;d say the feature I most like in Rails is undoubtedly the &lt;a href=&quot;http://guides.rubyonrails.org/asset_pipeline.html&quot;&gt;Rails Asset Pipeline&lt;/a&gt;.
It is an assets processor that uses &lt;a href=&quot;https://github.com/sstephenson/sprockets&quot;&gt;sprockets&lt;/a&gt; and some conventions
to help us to declare our assets dependencies and split them in several files and mix different related
languages, that will basically compile to JavaScript and CSS. Examples of languages supported out of the box are
CoffeeScript and SCSS, that are better versions (in my opinion of course) than JavaScript and CSS.&lt;/p&gt;
&lt;p&gt;This tools take out most of the pain I have with JavaScript. The main reason I hate JavaScript is the lack of
an import (or require) statement to make it easier to write modular code. This is changing in ES6 but it will
take a while before all target browsers support such statement. With the Asset Pipeline I don&amp;#39;t have to worry
about it because I may use such &amp;quot;require&amp;quot; statements in comments that are processed by the Asset Pipeline
without having to resort to bad techniques like AMD (my opinion, of course).&lt;/p&gt;
&lt;p&gt;The Asset Pipeline is also well integrated with the routing system.&lt;/p&gt;
&lt;h3&gt;Automatic code reloading during development&lt;/h3&gt;
&lt;p&gt;Booting a Rails application may take a few seconds, so you can&amp;#39;t just load the entire application on each
request as you used to do in the CGI era. It would slow down the development a lot. Being able to automatically
reload your code so that you have a faster development experience is a great tool provided by Rails. It is far
from simple to implement it properly and people often overlook this feature because it always worked great for
most people. Creating an automatic-reloading framework for other languages can be even harder. Try to take a
look at what some Java reloading frameworks are doing if you don&amp;#39;t believe.&lt;/p&gt;
&lt;h3&gt;Control over routes&lt;/h3&gt;
&lt;p&gt;This is supported by most frameworks nowadays but I always wanted this feature when I used to create web sites
in Perl long ago. But not all frameworks will make it easy for you to get a &amp;quot;site map&amp;quot; and see all your
application routes at once.&lt;/p&gt;
&lt;h3&gt;Dependency Management&lt;/h3&gt;
&lt;p&gt;Rails is the main reason why the genius Yehuda Katz decided to create Bundler, the best software dependency
management software I know about. Bundler is independent from Rails but I&amp;#39;d say Rails has the credits for
inspiring Yehuda to create Bundler but I may be wrong, of course. Ruby had RubyGems for a long while but it
suffered from the same problems as Maven.&lt;/p&gt;
&lt;p&gt;Without a tool like Bundler you have two options. Always specify the exact version of the libraries you
depend on (like Maven users often do) or be prepared to face several issues that may arise from different
gem versions that are resolved in different times cause by loose version requirements as it used to be the case
with RubyGems users.&lt;/p&gt;
&lt;p&gt;Bundler stores a snapshot of the current resolved gems in a file called Gemfile.lock so that it is possible to
replicate the entire gem versions under production or other developer&amp;#39;s computer without having to specify
exact version matches in your dependency file (Gemfile).&lt;/p&gt;
&lt;h3&gt;Great testing tools availability&lt;/h3&gt;
&lt;p&gt;I don&amp;#39;t write integration tests in Grails because it is too slow to boot up the entire framework when I only
want to test my domain classes (models in Rails terminology). Writing integration tests in Rails is certainly
slower than writing unit tests but it is feasible to write them because Rails boots in a few seconds in the
application I maintain. So it is okay to write some integration tests in Rails. I used to use Capybara to write
tests for views/controllers interaction but I ended up giving up on this approach preferring to write JavaScript
specs to test my front-end code in a much faster way and simply mock jQuery.ajax using my own testing frameworks,
&lt;a href=&quot;https://github.com/rosenfeld/oojspec&quot;&gt;oojspec&lt;/a&gt; and &lt;a href=&quot;https://github.com/rosenfeld/oojs&quot;&gt;oojs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For simple integration tests that only touch the database I don&amp;#39;t need to even load the entire Rails application,
which is much faster. I find this flexibility really awesome and makes test writing a much pleasant task.&lt;/p&gt;
&lt;p&gt;Other tools that help writing tests in Rails apps are RSpec and FactoryGirl among many others. Most of them can
be used outside of Rails scope, but when comparing Rails to non-Ruby web frameworks, it is great to point out
how writing web applications with Rails will make automatic testing an easier task than with other languages.&lt;/p&gt;
&lt;h3&gt;The Rails guides and community&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;http://guides.rubyonrails.org/&quot;&gt;Rails guides&lt;/a&gt; are really fantastic and cover most of the common tasks you
need when programming a web applications with Rails. Also, anyone is free to commit any changes to the guides
through the public repository &lt;a href=&quot;https://github.com/lifo/docrails&quot;&gt;docrails&lt;/a&gt; and that seems to work great.
I&amp;#39;ve even suggested this approach to the Grails core developers a while ago and it also seems this is working
great for them as well as their documentation improved a lot since then.&lt;/p&gt;
&lt;p&gt;Besides the guides there is plenty of resources about Rails on-line. Many of them are free. There are books
(both print and e-books, paid or free), tutorials and several articles covering many topics of web programming
in the context of a Rails application. There are even books focused on testing applications, like The RSpec Book,
by David Chelimsky. I haven&amp;#39;t found any books focused on testing for Grails or Groovy applications for instance.
And I only know about one book focused on JavaScript testing, by Christian Johansen, the author of Buster.js,
Sinon.js and one of the maintainers of the Gitorious project.&lt;/p&gt;
&lt;p&gt;Rails has a solid community behind it. There are several Rails committers applying many patches everyday and
the framework seems to be stronger than ever. You&amp;#39;ll find many useful gems for most tasks you&amp;#39;d think of. They&amp;#39;re
usually well integrated to Rails and you may have a hard time if you decide to use another Ruby web framework.&lt;/p&gt;
&lt;p&gt;Most of the gems are hosted on GitHub, which is part of the Rails culture I&amp;#39;d say. That helps a lot to contribute
back to those gems by adding new features or fixing bugs. And although pull requests are usually merged pretty
fast, you don&amp;#39;t even have to wait for it to be merged. You can just instruct Bundler to get that gem from your
own fork on GitHub and that is amazing (I wasn&amp;#39;t kidding when I said Bundler is the best software management
tool I&amp;#39;m aware of).&lt;/p&gt;
&lt;h3&gt;Security&lt;/h3&gt;
&lt;p&gt;Despite all critical security holes found on Rails and other Ruby libraries/gems that popped out recently, Rails
takes security very seriously. Once security issues are found they&amp;#39;re promptly fixed and publicly communicated
so that users can upgrade their Rails applications. I&amp;#39;m not used to see this attitude in most other frameworks/
libraries I&amp;#39;ve worked with.&lt;/p&gt;
&lt;p&gt;Rails also employs some security enhancements to web applications out-of-the-box by default, like CSRF protection
and provides a &lt;a href=&quot;http://guides.rubyonrails.org/security.html&quot;&gt;really great security guide&lt;/a&gt; that everyone should
read, even non-Rails developers.&lt;/p&gt;
&lt;h2&gt;How Rails gets on my way?&lt;/h2&gt;
&lt;p&gt;Even though Rails is currently my favorite web framework, it is not perfect. As a matter of fact there are
actually many things I don&amp;#39;t like in Rails and this is what this section is all about and also the main
motivation for writing this article. The same can be told about Ruby, which is my preferred language, but also
has its drawbacks. Not exactly Ruby the language, but the MRI implementation. I&amp;#39;ll get in details in the proper
section.&lt;/p&gt;
&lt;h3&gt;Monolithic design&lt;/h3&gt;
&lt;p&gt;Rails is not only a web framework and this is really bad from my point of view.&lt;/p&gt;
&lt;p&gt;Rails release strategy is to keep the version of all its major components the same one. So, when Rails 3.2.12 is released it will also release ActiveRecord 3.2.12, ActiveSupport 3.2.12, ActionPack 3.2.12, etc. Even if it is
a single security fix on ActiveRecord all components will have their version increased. This will also force you
to upgrade your ORM if you decide to upgrade your web framework.&lt;/p&gt;
&lt;p&gt;ActiveSupport should be maintained in a separate repository for instance as it is completely independent from
Rails. The same should be true for ActiveRecord.&lt;/p&gt;
&lt;h4&gt;The ActiveRecord case&lt;/h4&gt;
&lt;p&gt;The ORM is a critical part of a web application built on top of a RDBMS. It doesn&amp;#39;t make any sense to me to
assume it is part of a web framework. It is not. Its concerns are totally orthogonal (or at least they should
be). So, what happens if you want to upgrade your web framework to make use of a new feature like streaming
support? What if the newest ActiveRecord bundled with the latest Rails release has incompatible changes in its
API? Why should you be forced to upgrade ActiveRecord when you&amp;#39;re only interested in upgrading Rails, the web
framework?&lt;/p&gt;
&lt;p&gt;Or, what if you love ActiveRecord but are not developing web applications or you&amp;#39;re using another web framework?
Why would you have to contribute to Rails repository when you want to contribute to ActiveRecord? Or why don&amp;#39;t
you have a separate discussion list for ActiveRecord? A separate site and API documentation?&lt;/p&gt;
&lt;p&gt;I solved this problem myself a while ago by replacing ActiveRecord by Sequel and disabling AR completely in my
application. Luckily enough I find Sequel has a much better API and solid understanding about how RDBMS are
supposed to be used and knows how to take advantage of their features, like transactions, triggers and many
others. Sequel will actually advise you to prefer triggers over before/after/around callbacks in your code for
many tasks. This is in line with my own feelings about how RDBMS should be used.&lt;/p&gt;
&lt;p&gt;Also, for a long while ActiveRecord didn&amp;#39;t support lazy interfaces. Since I&amp;#39;ve stumbled over Sequel several
years ago I really loved its API and always used it instead of AR for some of my Ruby scripts, that weren&amp;#39;t
related to Rails apps. But for my Rails applications I always tried to avoid adding more dependencies because
most gems will just assume you&amp;#39;re using ActiveRecord.&lt;/p&gt;
&lt;p&gt;But I couldn&amp;#39;t be more wrong. Since I decided to move over to Sequel I never regretted my decision.
It is probably one of the best decisions I&amp;#39;ve made in the last few years. I&amp;#39;m pretty happy with Sequel and
its mailing list support. The documentation is great and I have great control over the generated queries, which
is very important to me as I often need complex queries in my applications. ActiveRecord is simply too way
limited.&lt;/p&gt;
&lt;p&gt;And even if Arel could help me to write such queries it is badly documented and is considered a private
interface, which means I shouldn&amp;#39;t be relying on its API when using ActiveRecord because theorically AR could
change its internal implementation anytime. And the public API provided by AR is simply too poor for the kind
of usage I need.&lt;/p&gt;
&lt;p&gt;Migrating to Sequel brought other benefits as well. Now the ORM and the web framework can be independently
upgraded. For instance, recently there was a security issue found in ActiveRecord which triggered a whole
Rails release which I didn&amp;#39;t have to upgrade because it didn&amp;#39;t affect Sequel.&lt;/p&gt;
&lt;p&gt;Also, I requested a feature in Sequel a while ago and it got implemented and merged in master a day or two after
my request. I tested it on my application by just instructing Bundler to use the version on master. Then I found
a concurrency issue with the new feature that affected our deployment on JRuby. In the same day I reported the
issue it got fixed on master and I could promptly use it without having to change any other bit of my
application.&lt;/p&gt;
&lt;p&gt;Jeremy Evans is also very kind when replying to questions in Sequel&amp;#39;s mailing list and will provide great
insightful advices once you explain what you&amp;#39;re trying to achieve in your application. He is also very
knowledgeable with regards to relational databases. Sequel is really carefully thought and cares a lot
about databases, concurrency and many more details. I couldn&amp;#39;t recommend it better to anyone that cares
about RDBMS.&lt;/p&gt;
&lt;h3&gt;Lack of a solid database understanding from the main designer&lt;/h3&gt;
&lt;p&gt;When I first read about Rails, in 2007, my only previous experience with databases was with Firebird when
people used to use Delphi a lot in Brazil. I really loved Firebird but I knew I would have to find something
else because Firebird wasn&amp;#39;t often used in web applications and I wanted to use something that was well
supported by the community. I also wanted a free database so the options were basically either MySQL or
PostgreSQL. I wasn&amp;#39;t really much interested on what database to use since I believed all RDBMS would be
essentially the same and I haven&amp;#39;t experienced any issues with Firebird. &amp;quot;It all boils down to SQL&amp;quot; I used
to think. So I&amp;#39;ve just made a small research in the web and I found lots of people complaining about MySQL
and no one complaining about PostgreSQL. I wasn&amp;#39;t really interested in knowing what people were talking about
MySQL and simply decided to go with PostgreSQL at the time since I had to choose one.&lt;/p&gt;
&lt;p&gt;A few years later I moved to another company that also happened to use PostgreSQL. Then I used it for 2 more
years (4 in total). When I moved my job again, this time the application used a MySQL database. &amp;quot;No problems&amp;quot;
I thought as I still believe it all boils down to SQL in the end. Man, I was completely wrong!&lt;/p&gt;
&lt;p&gt;After a few days working with MySQL, I noticed too many bugs and bad design decisions that I decided after an
year to finally migrate the database to PostgreSQL.&lt;/p&gt;
&lt;p&gt;But with so many good conventions that you get when you decide to use Rails, the documentation initially used
to use MySQL in the examples. Since lots of people really didn&amp;#39;t have a strong opinion about which database
vendor to choose from. That lead the community that was being formed to adopt MySQL in mass initially.&lt;/p&gt;
&lt;p&gt;Fortunately it seems the community understands now that PostgreSQL is a much better database but I&amp;#39;d still
prefer Rails to recommend towards PostgreSQL in the Getting Started guides.&lt;/p&gt;
&lt;p&gt;An example of how bad Rails opinions are over RDBMS is that ActiveRecord doesn&amp;#39;t even support foreign keys,
one of the key concepts in RDBMS, in their migrations DSL. That means that the portable Ruby format of the
current database schema is not able to restore foreign keys. Hibernate, the de-facto ORM solution for Java-based
applications, does support foreign keys. It will even create the foreign keys for you if you declare a belongs-to
relationship in your domain classes (models) and ask Hibernate to generate the migration SQL.&lt;/p&gt;
&lt;p&gt;If your application needs to support multiple database vendors, I&amp;#39;d recommend you to forget about schema.rb and
simply run all migrations whenever you want to create a new database (like a test db, for instance). If you
only have to care about a single DB vendor, like me, then just change the AR schema_format to use :sql instead of
:ruby. If you don&amp;#39;t care about foreign keys, you&amp;#39;re just plain wrong.&lt;/p&gt;
&lt;p&gt;I believe David Heinemeier Hansson is really a smart guy despite what some people might say. I just think
he hasn&amp;#39;t focused much on databases before creating Rails or he wouldn&amp;#39;t use MySQL. But there are many other
right decisions behind Rails and I find it really impressive the boom DHH has brought to web development
frameworks. People often say he is arrogant between other adjectives. I don&amp;#39;t agree. He has a strong opinion
about many subjects. So have I and many others. This shouldn&amp;#39;t be seen as impoliteness or arrogance.&lt;/p&gt;
&lt;h3&gt;Some arrogant core members&lt;/h3&gt;
&lt;p&gt;People have similar opinion about Linus Torvalds when he is right to the point in his phrases and opinions.
He also has strong opinions and a sense of humor that many don&amp;#39;t understand.  I just feel people get often
easily offended for no good reason these days, which is unfortunate. I have to be extra careful when writing
to some lists in the Internet that seems to be even more affected than the usual ones. I have received often
really aggressive responses in a few mailing lists for stating my opinions in direct ways that people often
consider a rude behavior when I call it a honest and direct opinion. I&amp;#39;m trying to avoid those opinions in some
list so that people don&amp;#39;t get mad with me.&lt;/p&gt;
&lt;p&gt;I really don&amp;#39;t know those people and I don&amp;#39;t have anything against them.
Believe me or not, I&amp;#39;m a good person and have tons of friends and I meet with them very often and they
don&amp;#39;t get offended when I&amp;#39;m direct to the point or when I state my strong opinions even when they don&amp;#39;t agree
with me. With my closest friends (and even some not that close) I would refer this as the expression 
&amp;quot;after all, I&amp;#39;m not a girl&amp;quot; in a tone of joke but I can&amp;#39;t tell such things in the Internet or people will
criticize me to dead. &amp;quot;You sexist! What do you have against girls?&amp;quot; Nothing at all, it is just an expression
often used with humor in my city at least... I love my wife and my daughter is about to born and I&amp;#39;m pretty
excited about that. I just think people take some phrases or expressions too seriously.&lt;/p&gt;
&lt;p&gt;If you ever have the chance to talk to my friends they will tell you I&amp;#39;m not the kind of guy seeking conflicts
but they will tell you that I have lots of strong opinions and that I&amp;#39;m pretty honest and direct about them.
They just don&amp;#39;t find it rude but healthy. And I expect the same from them.&lt;/p&gt;
&lt;p&gt;It is just sad when I find some angry response from Rails core members in the mailing list for no good reason.
If I call some Rails behavior stupid that take it on personal and will threaten stopping helping me because
they take my opinion as a personal attack as if I was calling them stupid people. I don&amp;#39;t personally know any
of them. How could I find any of them stupid? They are probably much smarter than me but that doesn&amp;#39;t mean
I can&amp;#39;t have my own opinions about some decisions behind Rails and find some of them stupid, which doesn&amp;#39;t mean
others can disagree with me and think that my way of thinking is stupid. I won&amp;#39;t take it as a personal attack.
I swear.&lt;/p&gt;
&lt;p&gt;On the other way, I find some of their attitudes really bad. For instance, if you ask for change some behavior in
Rails or any of its components some will reply: &amp;quot;send a pull request and we can discuss it. Otherwise we won&amp;#39;t
take time to just discuss the ideas with words. Show us code&amp;quot;. I don&amp;#39;t usually see this behavior in most other
communities I&amp;#39;ve participated. That basically means: &amp;quot;we don&amp;#39;t care that you spend your valuable time in a code
that wouldn&amp;#39;t ever be merged to our project because we don&amp;#39;t agree with the base ideas&amp;quot;. There are many things
that can be discussed without code. Asking someone to invest their time writing some code that will be later
rejected when it could be rejected before is quite offending in my point of view.&lt;/p&gt;
&lt;p&gt;By the way, that is the reason I don&amp;#39;t spend much time in complex patches to Rails. I&amp;#39;ve done that once long ago
and I didn&amp;#39;t get feedback from core developers after a while even after spending a considerate amount of time
in the patch and adapting many requested changes to it even though I didn&amp;#39;t agree with the changes. So I&amp;#39;d say
that my user experience for many libraries is just great but that is not usually the case with the Rails core
mailing list. Some of those core developers really believe they&amp;#39;re God gifts to the world which makes it hard
to argument with them in several aspects. And if you state your strong opinion about some subject you may be
seen as rude and they won&amp;#39;t want to talk to you anymore...&lt;/p&gt;
&lt;p&gt;Of course different people will have different experiences but I believe Rails is not the friendlier web
framework in my particular case. The Ruby-core list is a totally different beast and I can&amp;#39;t remember any
bad experience I had when talking to Matz, Kosaki, Shugo, Nobu and many others. I also had a great experience
in the JRuby mailing list, with Charles Nutter and many others. I&amp;#39;ve also talked about the great experience with
Jeremy Evans in the Sequel mailing list. I just don&amp;#39;t understand why the Rails core team doesn&amp;#39;t seem to tolerate
me. I don&amp;#39;t have any personal issues with any of them. But I don&amp;#39;t usually have a great experience there either
so I avoid writing to that list sometimes.&lt;/p&gt;
&lt;p&gt;Even after publishing my article with my strong (bad) opinions about Grails I don&amp;#39;t remember any bad experience
when talking to them in their list. And I know they read my article as it became somewhat popular in the Grails
community and I got even some replies from some of the Grails maintainers themselves.&lt;/p&gt;
&lt;h3&gt;The Rails API documentation&lt;/h3&gt;
&lt;p&gt;I remember that one of strong features of Rails 1 was the great API documentation. During the rewrite of Rails 3
lots of great documentation was deleted in the process and either got lost or was moved to the Rails guides.&lt;/p&gt;
&lt;p&gt;Currently I just stop trying to find any documentation by looking at the API documentation site. I used to do
that a lot in the Rails 1 era. So sad the current state is really bad to the point that I find it almost unusable
preferring to find the answers to what I&amp;#39;m looking for on StackOverflow, asking on mailing lists, digging into
the Rails source code or by other means. If I&amp;#39;m lucky, the information I&amp;#39;m looking for is documented in the
guides, but otherwise I&amp;#39;ll have to spend some time searching for it.&lt;/p&gt;
&lt;h3&gt;YAML used instead of plain Ruby to store settings&lt;/h3&gt;
&lt;p&gt;Rails provides us 3 environments by default: development, production and test. But in all projects I&amp;#39;ve worked
with I always had a staging environment as well. Currently our deployment strategy involves even more
environments. Very soon we realized that it wasn&amp;#39;t easy to manage all those environments by having to tweak so
many configuration files: config/database.yml, config/mongo.yml,
config/environments/(development|test|production).rb and many other kept popping up. Also, when you run tasks
like &amp;quot;rake assets:precompile&amp;quot; it will use the production environment by default while it would use development
by default for most tasks.&lt;/p&gt;
&lt;p&gt;Every time we needed to create a new environment it was too much work for us to manage. So we ended up by
dropping all those YAML files and simple symlink config/settings.rb to config/settings/environment_name.rb.
We also symlinked config/environments/*.rb to all point to the same file. We would also manage the different
settings in config/settings.rb. So we have staging.rb, production.rb, test.rb, development.rb and a few others
under config/settings. We simply symlink the one of interest in config/settings.rb, which is ignored by Git.&lt;/p&gt;
&lt;p&gt;The only exception is that test.rb is always used when running tests. That worked out much better for us and
it is much easier for us to create a new environment and have all settings, like Redis, Mongo, PostgresSQL,
integration URLs and many more settings grouped in a single file symlinked as settings.rb. Pretty simple to
figure out what needs to be changed as well as base our settings on top of another existing environment.&lt;/p&gt;
&lt;p&gt;For instance, staging.rb would require production.rb and overwrite a few settings. This is a much improved
way of handling multiple environments than the standard way most Rails applications implement, by maintaining
sparse YAML files among some DSLs written in Ruby (like Devise and others).&lt;/p&gt;
&lt;p&gt;I believe the Grails approach of allowing external overrides Groovy files to better configure the application
in a per environment basis a better convention to follow than the one suggested by Rails. What is the
advantage of YAML(.erb) files over plain Ruby configuration files?&lt;/p&gt;
&lt;h3&gt;Deployment / scalability&lt;/h3&gt;
&lt;p&gt;One of the main drawbacks of Rails in my opinion is that it waited too long to start thinking seriously about
threaded deployment. Threads were often successfully used by many web frameworks in many languages but for
some reason it has been neglected in the Ruby/Rails community.&lt;/p&gt;
&lt;p&gt;I believe there are two major reasons for that. The Ruby community usually focus on MRI as the Ruby
implementation of choice and MRI has a global interpreter lock that prevents multiple threads running Ruby code
to be executed in parallel. So, unless your application is IO intensive you wouldn&amp;#39;t get much benefits from
using a threaded approach. I blame MRI for this as they don&amp;#39;t really seem to be bothered by GIL. I mean, they
would probably accept a patch to fix the issue but they&amp;#39;re not willing to tackle the issue themselves as they
believe forking is just as good solution. And this leads to the next reason, but before that I&amp;#39;d just like to notice that JRuby always performed great in multi-thread environments and that I think Rails took too long before
taking this approach more seriously and consider JRuby as a viable deployment environment for the threaded 
approach. Threads are in my opinion the proper way of handling concurrency in most cases and I really think
that should be the default one as in most other web frameworks in other languages.&lt;/p&gt;
&lt;p&gt;Now to the next reason why people usually prefer multi-process over multi-thread deployment in the Ruby
community. I&amp;#39;ve asked once on the MRI mailing list what was the status of threads support in MRI. Some
core committers told me that they wouldn&amp;#39;t invest time on getting rid of the GIL mainly because they feel
forking was a better fit most of the times. It avoided some concurrency issues one might experience when
using threads. They also argued that they didn&amp;#39;t want Ruby programmers to have to worry about thread-safety,
locks, etc. I don&amp;#39;t really understand why people are so afraid of threads and why they think they&amp;#39;re so
hard to use in a safe way. I&amp;#39;ve worked with threaded applications for many years and I didn&amp;#39;t have this bad
experience several developers complain about.&lt;/p&gt;
&lt;p&gt;I really miss proper threading support in MRI because a threaded deployment strategy allows much better memory
usage under high load than the multi-process approach and it is much easier to scale. That is also the reason
why I think it should be the default. It would avoid the situation where people have to worry about deployment
strategies too early in the process. They think about load balancers, proxy, etc. when a single threaded instance
would be enough for a long time before your application starts having throughput issues. But if you deploy
a single process using a single-thread approach, you&amp;#39;ll very soon realize it doesn&amp;#39;t scale even to your few
users. That&amp;#39;s why I believe Rails should promote threaded deployment by default since it is easier to start
with.&lt;/p&gt;
&lt;p&gt;But the MRI limitation makes this decision hard to make. Specially because the development experience is usually
much better on MRI than it is on JRuby. Tests will start running much faster on MRI and some tools that will
speed up it even more won&amp;#39;t work well on JRuby, like Spork and similar gems.&lt;/p&gt;
&lt;p&gt;So, I can&amp;#39;t really recommend any solution to this deployment problem with Rails. Currently we&amp;#39;re using
Unicorn (multi-process) + MRI to deploy our application but I really believe this isn&amp;#39;t the optimal solution to
web deployment and I&amp;#39;d really love to see this situation improved in the next years.&lt;/p&gt;
&lt;p&gt;Apart from the deployment issues I always missed streaming support in Rails but I haven&amp;#39;t created a section
about it in this article because Rails master already seems to support it and Rails 4 will probably be released
soon.&lt;/p&gt;
&lt;h4&gt;The MRI shortcomings&lt;/h4&gt;
&lt;p&gt;When it comes down to the MRI implementation itself, the lack of a good thread support isn&amp;#39;t the only thing
that annoys me.&lt;/p&gt;
&lt;h5&gt;Symbols vs Strings confusion&lt;/h5&gt;
&lt;p&gt;I can&amp;#39;t really understand the motivation for symbols to exist in Ruby. They cause more harm than good. I&amp;#39;ve
discussed my opinions already a lot &lt;a href=&quot;https://bugs.ruby-lang.org/issues/7792&quot;&gt;here&lt;/a&gt; if you&amp;#39;re curious about it.&lt;/p&gt;
&lt;p&gt;To make things worse, if the harm and confusion caused by symbols with no apparent benefits wasn&amp;#39;t a reason
good enough to get rid of them, attackers are often trying to find new ways to create symbols in web
applications. The reason for that is that symbols are not garbage collected. If you employ the threaded
strategy when deploying your application and an attacker could get your application to create more symbols
your application would crash at some point due to memory leak since symbols are never garbage collected,
&lt;a href=&quot;https://bugs.ruby-lang.org/issues/7791&quot;&gt;although it might change at some point&lt;/a&gt;.&lt;/p&gt;
&lt;h5&gt;Autoloading&lt;/h5&gt;
&lt;p&gt;Autoload is a Ruby feature that allows some files to be lazy loaded, thus improving the start-up time to boot
Rails in development mode for instance. I&amp;#39;m curious to know if the lazy approach really makes such a big
difference when comparing to just require/load all files. And if it does, couldn&amp;#39;t this load time be improved
somehow?&lt;/p&gt;
&lt;p&gt;The problem with autoload is that it can create bugs that are hard to track and I indeed have been bitten by a
bug caused by autoload. Here is an example of how it can be triggered:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;#./test.rb:
autoload :A, &amp;#39;a&amp;#39;
require &amp;#39;a/b&amp;#39;

#./lib/a.rb:
require &amp;#39;a/b&amp;#39;

#./lib/a/b.rb:
module A
  module B
  end
end

#ruby -I lib test.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Design opinions&lt;/h3&gt;
&lt;p&gt;I really prefer code that makes its dependencies very explicit. Some languages, like Java and most static ones,
will force this to happen. But that is not the case in Ruby.&lt;/p&gt;
&lt;p&gt;Rails prefers to follow the Don&amp;#39;t-Repeat-Yourself principle instead of being always explicit about each file
dependencies. That makes it impossible for a developer to use a small part of some Rails component because
they are designed in such a way that you have to require the entire component and not just part of it even if
that file is pretty independent from everything else.&lt;/p&gt;
&lt;p&gt;Recently I wanted to use some code in ActionView::Helpers::NumberHelper in my own class ParseFormatUtils. Even
though my unit tests worked fine when doing that, my application would fail due to circular dependencies issues
caused by autoload and the way the Rails code is designed.&lt;/p&gt;
&lt;p&gt;In my applications it is always very clear what each class is responsible for. Rails controllers will only be
concerned about the web layer and most of the logic will be coded in a separate class or module and tested
independently. That makes testing (both manual and automated) much easier and faster and also makes it easier
for the project developers to understand and follow the code.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m really sad that Rails doesn&amp;#39;t share my point of view with regards to that and thinks DRY principle is more
important than being explicit about all dependencies in each file.&lt;/p&gt;
&lt;h2&gt;Final notes&lt;/h2&gt;
&lt;p&gt;Even though there are several aspects of Rails I dislike I couldn&amp;#39;t actually suggest a better framework for
a web developer. If I weren&amp;#39;t using Rails I&amp;#39;d probably be using some other Ruby web framework and create some
kind of Asset Pipeline and automatic reload mechanism but I don&amp;#39;t really think it would worth the benefits.&lt;/p&gt;
&lt;p&gt;All Rails issues are manageable in my opinion. I think other frameworks I&amp;#39;ve worked with are not manageable.
The have some fundamental flaws that prevent me from actually considering them if the choice is mine to make.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve reported some serious bugs to Grails JIRA almost an year ago for instance with test cases included and they haven&amp;#39;t been fixed yet. This is something to be really worried about. All Rails issues are easily manageable in
my opinion.&lt;/p&gt;
&lt;p&gt;I may not deploy my application they way I&amp;#39;d prefer but Unicorn is currently fitting our application needs well
enough. I can&amp;#39;t require just &amp;#39;action_view/helpers/number_helper&amp;#39; but requiring full &amp;#39;action_view&amp;#39; instead isn&amp;#39;t
that bad either.&lt;/p&gt;
&lt;p&gt;I&amp;#39;d just like to state that even though I don&amp;#39;t consider Rails/Ruby to be perfect, they&amp;#39;re still my choice when
it comes down to general web development.&lt;/p&gt;
</content:encoded></item><item><title>Client-side code testing with oojspec</title><link>https://rosenfeld.page/articles/programming/2012_07_20_client_side_code_testing_with_oojspec/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2012_07_20_client_side_code_testing_with_oojspec/</guid><pubDate>Fri, 20 Jul 2012 12:16:00 GMT</pubDate><content:encoded>&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;I&amp;#39;ve been working solely on single-page web applications for the last 3 years. The client-side code
I write is something about 70% of my total code and this percentage has been increasing over the
time. While there are excelent tools to work with for testing back-end code in Ruby (RSpec,
Capybara, FactoryGirl) I still miss a great framework for writing tests for my client-side code.
At least that used to be the case.&lt;/p&gt;
&lt;p&gt;We currently have tons of great alternatives for writing client-side code: Knockout.js, Angular.js,
Ember.js, Serenade.js and a thousand more. They&amp;#39;re awesome for helping us to build single-page
applications despite JavaScript being such an horrible language that is only now considering
modular programming in ES6, but this will take some years before we can rely on its support :(&lt;/p&gt;
&lt;p&gt;Even some languages, like the awesome CoffeeScript, were born to try to make JavaScript code writing
more pleasant, although they&amp;#39;re still unable to provide something like a require/import statement.
After all, they still need to compile to JavaScript :( Fortunately there are some assets
pre-processor tools available to help us writing more modular code, like the Rails Asset Pipeline
that will allow me to write &amp;quot;require&amp;quot;s as comments in my source headers and that has greatly reduced
the pain that is working with JavaScript for me.&lt;/p&gt;
&lt;p&gt;But when it comes to integration tests for my client-side code I&amp;#39;ve never felt great with regards to
current available testing frameworks for JavaScript. I&amp;#39;ve been using Jasmine for a long time but I
always missed a &lt;em&gt;beforeAll&lt;/em&gt;/&lt;em&gt;afterAll&lt;/em&gt; feature. A lot! Mocha/Chai bundle seems great, but
unfortunately they require a JavaScript feature that is not present in older Internet Explorer,
which I still must support in my products :( Finally, Buster.js is a great modular framework but it
is just not suitable for the way I write integration tests because of their random execution order.&lt;/p&gt;
&lt;p&gt;Konacha is a great gem that took the right approach on providing some conventions to tests
organization being well integrated to the Rails Asset Pipeline. But it used Mocha/Chai...
So I created a while ago the
&lt;a href=&quot;https://github.com/rosenfeld/rails-sandbox-assets&quot;&gt;rails-sandbox-assets&lt;/a&gt; gem with the same goal
of Konacha of introducing some conventions to test organization and integrating to the Rails Asset
Pipeline. But differently from Konacha, it is framework-agnostic. In fact, I&amp;#39;ve written adapters
for all mentioned testing frameworks in this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rails_sandbox_jasmine&quot;&gt;rails_sandbox_jasmine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rails_sandbox_mocha_chai&quot;&gt;rails_sandbox_mocha_chai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/rails-sandbox-busterjs&quot;&gt;rails-sandbox-busterjs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And recently my own testing framework built on top of Buster.js reporter and 
&lt;a href=&quot;https://github.com/busterjs/referee&quot;&gt;assertions&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/oojspec&quot;&gt;oojspec&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All those Ruby gems integrate to the Rails Asset Pipeline and all you have to do is creating your
tests/specs in specific locations and they will be all automatically loaded by the test runner.
Just like it happens with Konacha, this test runner server will only serve the application assets
(JavaScript, CSS, images) and won&amp;#39;t touch any controllers, models or any other Ruby code.&lt;/p&gt;
&lt;p&gt;It is even possible to integrate the Rails Asset Pipeline to non-Rails application, as I&amp;#39;ve done
with this &lt;a href=&quot;https://github.com/rosenfeld/grails-oojs&quot;&gt;Grails application&lt;/a&gt; as a proof-of-concept.
See &lt;a href=&quot;https://github.com/rosenfeld/oojs_assets_enabler&quot;&gt;oojs_assets_enabler&lt;/a&gt; for a minimal Rails
application that can be integrated to any other server framework to enable you to use the power
of the assets pre-processor and testing tools with your non-Rails application.&lt;/p&gt;
&lt;p&gt;If you don&amp;#39;t like the idea of using the Rails Asset Pipeline (because you&amp;#39;re averse to Rails or
Ruby names), even if it won&amp;#39;t require from you any Ruby knowledge, you can still use oojspec
standalone. I&amp;#39;ve created some jsfiddle&amp;#39;s examples in
&lt;a href=&quot;https://github.com/rosenfeld/oojspec&quot;&gt;oojspec README&lt;/a&gt; demonstrating how to do that (or do you
think that JsFiddle has included support for Rails as well?! ;) ).&lt;/p&gt;
&lt;p&gt;Enough with small talking!&lt;/p&gt;
&lt;h1&gt;Getting started&lt;/h1&gt;
&lt;p&gt;Take a look at the reporter first, to see &lt;a href=&quot;http://oojspec.herokuapp.com/&quot;&gt;how it looks like&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yes, I know it is failing. This is on purpose so that you can see the stack-traces and how failures
and errors look like.&lt;/p&gt;
&lt;h2&gt;Setting-up the runner&lt;/h2&gt;
&lt;h3&gt;Rails applications&lt;/h3&gt;
&lt;p&gt;The oojspec gem will already provide you an HTML runner that will include all your tests/specs
located under test/javascripts/oojspec/&lt;em&gt;_test.js[.coffee] and
spec/javascripts/oojspec/&lt;/em&gt;_spec.js[.coffee] at your taste. Just include the &amp;quot;oojspec&amp;quot; dependency to
your Gemfile and run &amp;quot;bundle&amp;quot;.&lt;/p&gt;
&lt;p&gt;Stylesheets in [test|spec]/stylesheets/oojspec/*_[test|spec].css are also automatically included in
the HTML runner. You can just import the required CSS files from them.&lt;/p&gt;
&lt;h3&gt;Rails Asset Pipeline-enabled applications&lt;/h3&gt;
&lt;p&gt;If you want to take full advantage of the
&lt;a href=&quot;http://guides.rubyonrails.org/asset_pipeline.html&quot;&gt;Rails Asset Pipeline&lt;/a&gt;,
try to disassociate the &amp;quot;Rails&amp;quot; name from it first. It has nothing to do with Rails at all.
You don&amp;#39;t have to learn Ruby or Rails for taking advantage of it. Although, if you&amp;#39;re using Rails
you&amp;#39;ll be able to integrate your dynamic routes to your assets. But even if you aren&amp;#39;t you can
get pre-compilation and minifying tasks, automatic CoffeeScript compiling and, specially, the
ability of specifying dependencies between your sources by using special comments in your source
headers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// bowling_spec.js
// this will require bowling.js or bowling.js.coffee:
//= require bowling

describe(&amp;quot;Bowling&amp;quot;, function(){
  // ...
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please let me know if you&amp;#39;d like a more in-depth article on how to take full advantage of the
Rails Asset Pipeline with your non-Rails application.&lt;/p&gt;
&lt;p&gt;All you have to do is to follow the short instructions
&lt;a href=&quot;https://github.com/rosenfeld/grails-oojs&quot;&gt;here&lt;/a&gt;. This example has showed how to integrate
with Grails but basically all you have to do is to adapt it to add
&lt;a href=&quot;https://github.com/rosenfeld/oojs_assets_enabler&quot;&gt;this&lt;/a&gt; to your project.&lt;/p&gt;
&lt;h3&gt;No Rails integration at all&lt;/h3&gt;
&lt;p&gt;Okay, so you don&amp;#39;t see value in the Rails Asset Pipeline or you&amp;#39;re using your own tools for
pre-processing your assets. Then you&amp;#39;ll have to write an HTML runner yourself, which is also
pretty simple. &lt;a href=&quot;http://jsfiddle.net/rosenfeld/FWtaZ/&quot;&gt;Here is a working example in JsFiddle&lt;/a&gt;
on how to do it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;base href=&amp;quot;http://oojspec.herokuapp.com/&amp;quot; /&amp;gt;
  &amp;lt;meta http-equiv=&amp;quot;content-type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot;&amp;gt;

  &amp;lt;title&amp;gt;oojspec Test Runner&amp;lt;/title&amp;gt;

  &amp;lt;link href=&amp;quot;/assets/oojspec.css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
  &amp;lt;script src=&amp;quot;/assets/oojspec.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;oojspec.exposeAll()&amp;lt;/script&amp;gt;
&amp;lt;!-- put your code and tests/specs here in the right order of dependency:
  &amp;lt;script src=&amp;quot;/assets/first_spec.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&amp;quot;/assets/second_spec.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
--&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
  oojspec.autorun()
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Feel free to download oojspec.css and oojspec.js for faster local development first.&lt;/p&gt;
&lt;h2&gt;Describing your code&lt;/h2&gt;
&lt;p&gt;Now that we have our runner set up, it is time to describe our code by writing some tests/specs.&lt;/p&gt;
&lt;p&gt;You can do it with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;oojspec.describe(&amp;quot;Some description&amp;quot;, function(){
  this.example(&amp;quot;Basic stuff work :P&amp;quot;, function(){
    this.assert(true);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When using the oojspec gem, by default it will expose the &amp;quot;describe&amp;quot; function to the global (window)
namespace, although this can be disabled by adding the following line to your application.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;config.sandbox_assets.options[:skip_oojspec_expose] = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also when using CoffeeScript to write your specs (even if your code is written in JavaScript), that
example becomes more succinct. Also, I&amp;#39;m using the exported &amp;quot;describe&amp;quot; this time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;describe &amp;quot;Some description&amp;quot;, -&amp;gt;
  @example &amp;quot;Basic stuff work :P&amp;quot;, -&amp;gt; @assert true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you prefer to keep with JavaScript, but don&amp;#39;t want to type &amp;quot;this.&amp;quot; all the time, you can use an
alternative idiom:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;oojspec.describe(&amp;quot;Some description&amp;quot;, function(s){
  s.example(&amp;quot;Basic stuff work :P&amp;quot;, function(s){
    s.assert(true);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From within a description block, the following DSL keywords are available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;example/it/specify: all of them are aliases for declaring an example.&lt;/li&gt;
&lt;li&gt;describe/context: aliases for declaring a nested context/description.&lt;/li&gt;
&lt;li&gt;before/after/beforeAll/afterAll: hooks for code that should run before each, after each, before
all and after all examples of that description respectively.&lt;/li&gt;
&lt;li&gt;pending/xit: alias for declaring pending examples (or descriptions) whose block isn&amp;#39;t executed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Writing your examples&lt;/h2&gt;
&lt;p&gt;From within an example, you can use any assertion supported by the
&lt;a href=&quot;https://github.com/busterjs/referee&quot;&gt;referee library&lt;/a&gt;. All of them are
&lt;a href=&quot;http://busterjs.org/docs/assertions/&quot;&gt;well documented here&lt;/a&gt;. You can mix both assertions and
expectations in your examples. And you can even write your own
&lt;a href=&quot;http://busterjs.org/docs/assertions/#add&quot;&gt;custom assertions/expectations&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;oojspec.assertions.add(&amp;quot;isVisible&amp;quot;, {
  assert: function(actual) {
    return $(actual).is(&amp;#39;:visible&amp;#39;);
  },
  assertMessage: &amp;quot;Expected ${0} to be visible.&amp;quot;,
  refuteMessage: &amp;quot;Expected ${0} not to be visible.&amp;quot;,
  expectation: &amp;quot;toBeVisible&amp;quot;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Asynchronous examples&lt;/h3&gt;
&lt;p&gt;Sometimes you need to wait for certain conditions after taking some actions and those will most
probably happen in an async fashion. So, for letting you focus in the specs instead of having to
write polling functions yourself, oojspec borrows the waitsFor/runs approach from Jasmine.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;describe(&amp;quot;Some description&amp;quot;, function(s){
  s.example(&amp;quot;Operation was successful&amp;quot;, function(s){
    $(&amp;#39;button#create&amp;#39;).click();
    s.waitsFor(&amp;quot;dialog to pop up&amp;quot;, function(){
      return $(&amp;#39;#show-message-dialog:visible&amp;#39;).length &amp;gt; 0;
    });
    s.runs(function(s){
      s.expect(&amp;#39;#show-message-dialog&amp;#39;).toBeVisible();
    })
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use multiple waitsFor and runs blocks in the same example at your will.&lt;/p&gt;
&lt;h2&gt;Mocks&lt;/h2&gt;
&lt;p&gt;Sometimes mocks are really useful. Specially for creating fake HTTP servers for responding to your
application AJAX requests. But since they&amp;#39;re orthogonal to test runners, no mocking library is
included in oojspec. But I&amp;#39;d recommend you using the excellent &lt;a href=&quot;http://sinonjs.org/&quot;&gt;Sinon.js&lt;/a&gt;
mocking and stubing library. If you&amp;#39;re using the Rails Asset Pipeline, this is just a matter of
including  the &lt;a href=&quot;https://github.com/travisjeffery/sinon-rails&quot;&gt;sinon-rails gem&lt;/a&gt; to your Gemfile and
requiring it in your spec:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;//= require sinon
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sinon.js has a fake AJAX server built-in but if you always use jQuery for your AJAX requests you
might find my gem &lt;a href=&quot;https://github.com/rosenfeld/fake-ajax-server&quot;&gt;fake-ajax-server&lt;/a&gt; somewhat easier
to use.&lt;/p&gt;
&lt;h2&gt;Object-oriented testing&lt;/h2&gt;
&lt;p&gt;Specially when writing integration tests for my client-side code, I find it easier to describe a
group of behaviors like sequential examples that are depending on a given order. In those cases
I find it useful to share some state between them and taking an object-oriented approach would
take care of this.&lt;/p&gt;
&lt;p&gt;Suppose you have some class that you instantiate on your application load that will take care of
registering some jQuery live events which are never unregistered because it is not needed by your
application. So, you&amp;#39;re unable to instantiate such a class several times in &amp;quot;before&amp;quot; hooks because
you&amp;#39;d be registering the same events several times. In that case, you can instantiate it in a
&amp;quot;beforeAll&amp;quot; hook once in your suite.&lt;/p&gt;
&lt;p&gt;But then it will be impossible to get back to the original state. But I don&amp;#39;t see this as a major
issue. Suppose you have to test a dynamic tree, using the excellent
&lt;a href=&quot;http://mbraak.github.com/jqTree/&quot;&gt;jqTree library&lt;/a&gt;. You can start with an empty tree and add a test
for including a new item to the tree. Then you add another test for including a sub item to the
item created in your prior test. Then you add a test for moving it so that it becomes a sibling
of the first item. Then you add a test for deleting the first item and make sure only the last one
is kept. I don&amp;#39;t really mind if all those tests written for a &amp;quot;Tree Management&amp;quot; context are not
independent from each other. I find it easier to write those tests in this sequential order than
trying to make them independent.&lt;/p&gt;
&lt;p&gt;This is the main point where I find the other testing frameworks to be too limiting for me or they
don&amp;#39;t target the same browsers as I do.&lt;/p&gt;
&lt;p&gt;When writing non-oo tests with oojspec, &amp;quot;this&amp;quot; will refer to an object containing only the available
DSL for that context. This same DSL object is also sent as the first arguments to the blocks used
by example, context, runs, etc.&lt;/p&gt;
&lt;p&gt;On the other hand, when writing OO tests, you are in charge of specifying what will &amp;quot;this&amp;quot; refer to.&lt;/p&gt;
&lt;p&gt;By default, OO tests are &amp;quot;non-bare&amp;quot;, which means that the DSL will be merged with your &amp;quot;this&amp;quot;
object. This allows you to write &amp;quot;this.example&amp;quot; as before. But you can opt for using a &amp;quot;bare&amp;quot;
approach in which case you&amp;#39;ll handle the DSL through the first argument of the block.&lt;/p&gt;
&lt;p&gt;You can provide the description directly in the passed object or as the first argument as before.
It is only required that your object responds to runSpecs() as the entry point.&lt;/p&gt;
&lt;p&gt;Here are some examples:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// non-bare approach, with the description in the object itself:
describe({
      description: &amp;#39;Plain Object binding&amp;#39;,
      dialog: {dialog: true},
      runSpecs: function(){ this.example(&amp;#39;an example&amp;#39;, this.sampleExample); },
      sampleExample: function(){ this.assert(this.dialog.dialog); }
});

// traditional description syntax and a bare approach:
describe(&amp;#39;Bare description&amp;#39;, {
      bare: true,
      dialog: {dialog: true},
      runSpecs: function(s){ s.example(&amp;#39;an example&amp;#39;, this.sampleExample); },
      sampleExample: function(s){ s.assert(this.dialog.dialog); }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In case you prefer CoffeeScript, like me, you can find the &amp;quot;class&amp;quot; syntax somewhat easier to work
with. oojspec will instantiate a class in case it detects it is a class (its prototype responds to
runSpecs instead of the object itself). It even uses the constructor&amp;#39;s name if a description is not
provided.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;describe class # you can use an anonymous class as well
  @description: &amp;#39;Bare class&amp;#39;
  @bare: true

  runSpecs: (dsl)-&amp;gt;
    @dialog = dialog: true
    dsl.example &amp;#39;an example&amp;#39;, @anExample
    dsl.context &amp;#39;in some context&amp;#39;, @aContext
    dsl.describe NonBareClass

  anExample: (s)-&amp;gt; s.expect(@dialog).toEqual dialog: true

  # this.runs is not available from an example when using a bare approach
  aContext: (s)-&amp;gt; s.example &amp;#39;another example&amp;#39;, (s)-&amp;gt; s.refute @runs

class NonBareClass # description will be &amp;quot;NonBareClass&amp;quot;
  runSpecs: -&amp;gt;
    @dialog = dialog: true
    @example &amp;#39;an example&amp;#39;, @anExample
    @context &amp;#39;in some context&amp;#39;, @aContext

  anExample: -&amp;gt; @expect(@dialog).toEqual dialog: true

  # this.describe is never available from within an example
  aContext: -&amp;gt; @example &amp;#39;another example&amp;#39;, -&amp;gt; @refute @describe
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Real examples&lt;/h1&gt;
&lt;p&gt;This article is already long enough. I&amp;#39;ll try to find out some time in the future to focus in some
real use case to demonstrate how I write integration tests for my single-page applications using
some real application as an example.&lt;/p&gt;
&lt;h1&gt;Feedback&lt;/h1&gt;
&lt;p&gt;I&amp;#39;d really love to hear your feedback about oojspec. Please let me know what you think about it
by e-mail, GitHub, comments in this page or Twitter (rrrosenfeld). If you think you&amp;#39;ve found some
bug, please report it on &lt;a href=&quot;https://github.com/rosenfeld/oojspec/issues&quot;&gt;GitHub issues&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Client-side Object Oriented Programming and Testing</title><link>https://rosenfeld.page/articles/programming/2012_06_03_client_side_object_oriented_programming_and_testing/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2012_06_03_client_side_object_oriented_programming_and_testing/</guid><pubDate>Sun, 03 Jun 2012 19:52:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Despite the fact that I don&amp;#39;t like the JavaScript language, we can&amp;#39;t just avoid it.&lt;/p&gt;
&lt;p&gt;Client-side programming allows for better user experience and less network traffic
and is required for lots of web applications. I&amp;#39;ve been doing client-side code most
of my time since 2009 and it takes more and more of my time. I don&amp;#39;t think this is
gonna change.&lt;/p&gt;
&lt;p&gt;Although not perfect, CoffeeScript took a lot of the pain of writing JavaScript code
for me, although it still doesn&amp;#39;t provide any import/require feature as it has to
compile to JavaScript anyway. So, all examples in this article will be written in
CoffeeScript, but feel free to write your own tests and code in JavaScript if you prefer.&lt;/p&gt;
&lt;p&gt;Since we have a lot of our logic now in the client-side, it is time to take it much
more seriously. That means we must write specs (unit and integration ones) for our
client-side code as well. That has been a pain for me for a while, but I took some
time to release some code to help us with this task, and this is mostly what I&amp;#39;ll be
talking about in this article. Specially on client-side code integration testing.&lt;/p&gt;
&lt;p&gt;Although my released gems depend on Rails Asset Pipeline support, this article should
also guide you on how to easily write your specs for whatever server-side framework
you&amp;#39;ve chosen. I&amp;#39;ll provide an example on how to do that for a Grails application, but
you could apply the instructions for whatever other framework you want.&lt;/p&gt;
&lt;h2&gt;Design decisions&lt;/h2&gt;
&lt;p&gt;Feel free to skip this entire section.&lt;/p&gt;
&lt;h3&gt;Why the Rails Asset Pipeline?&lt;/h3&gt;
&lt;p&gt;I should state that I&amp;#39;m passionated about Ruby and that Rails is currently my web
framework of choice, so be warned that this is probably a biased opinion.&lt;/p&gt;
&lt;p&gt;The biggest mistake in the design of the JavaScript language in my opinion was the
lack of a require/import statement, which won&amp;#39;t allow us to easily split our
applications into modules. This was fixed for server-side JS applications by Node.js,
but is still an issue for client-side code (that running in web browsers).&lt;/p&gt;
&lt;p&gt;ES.Next is going to add modules support for JavaScript but it can take quite a while
before 99% of your client users will be using a browser that supports those modules.&lt;/p&gt;
&lt;p&gt;Currently I know two alternatives for dealing with dependency management in JavaScript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD, with implementations like RequireJS or LabJS, but I find this approach to be
too complicated to be practical and I&amp;#39;d rather avoid it;&lt;/li&gt;
&lt;li&gt;Concatenation by using some pre-processor tool that can process the dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Rails Asset Pipeline falls in this second category, just like the Grails Resources
plugin. But the Resources plugin will require you to set up your dependencies in a separate
file, while in the Rails Asset Pipeline you set up your dependencies as comments in your
asset (JavaScript and stylesheets) headers. I much prefer this approach as it reminds me
of regular require/import features existing in most programming languages. Also, differently
from the Rails Asset Pipeline, the Grails Resources plugin won&amp;#39;t support CoffeeScript
out-of-the-box.&lt;/p&gt;
&lt;p&gt;Also, the Rails Asset Pipeline is
&lt;a href=&quot;http://guides.rubyonrails.org/asset_pipeline.html&quot;&gt;well documented&lt;/a&gt;
and easily extended by the use of plugins (or Ruby gems if you prefer).&lt;/p&gt;
&lt;h3&gt;My application is not written in Rails!&lt;/h3&gt;
&lt;p&gt;I&amp;#39;m sorry about you, but this is not a reason for not reading this article. You can still
take advantage of the techniques and tools I describe here in whatever framework you&amp;#39;re
using. Just keep reading on.&lt;/p&gt;
&lt;h3&gt;Why &lt;a href=&quot;https://github.com/rosenfeld/oojspec&quot;&gt;oojspec&lt;/a&gt;?&lt;/h3&gt;
&lt;p&gt;Please read &lt;a href=&quot;2012-07-20-client-side-code-testing-with-oojspec&quot;&gt;this article&lt;/a&gt; for the reasoning
behind it. In short, oojspec is designed with integration tests in mind and an OO approach.&lt;/p&gt;
&lt;h3&gt;Why object-oriented JavaScript?&lt;/h3&gt;
&lt;p&gt;I really like OO programming and being able to easily share states. This allows me to write
maintainable code and specs in a modular way.&lt;/p&gt;
&lt;h3&gt;Why CoffeeScript?&lt;/h3&gt;
&lt;p&gt;I find code written in CS more concise and easier to read. It supports comprehensions,
destructuring assignment, splats, string interpolation, array range syntax, &amp;quot;class&amp;quot; and
&amp;quot;extend&amp;quot; keywords, &amp;quot;@attribute&amp;quot; as a shortcut to &amp;quot;this.attribute&amp;quot;, easy function bindings
through &amp;quot;=&amp;gt;&amp;quot;, and easier &amp;quot;for-in&amp;quot; and &amp;quot;for-of&amp;quot; constructions among several other great
language additions.&lt;/p&gt;
&lt;p&gt;On the other side I don&amp;#39;t like very much that &amp;quot;==&amp;quot; is translated to &amp;quot;===&amp;quot; and that &amp;quot;elvis?&amp;quot;
has a different meaning inside functions and a few other issues I can&amp;#39;t remember right now.&lt;/p&gt;
&lt;p&gt;But all in all, CS is a much better language than JS in my opinion. Even if you don&amp;#39;t want
to write CoffeeScript for your production code, you should consider using it at least for
your specs. But feel free to use JS for your specs too if you really dislike CS.&lt;/p&gt;
&lt;p&gt;So, with CS and the Rails Asset Pipeline which will provide a require-like mechanism,
client-side programming is no longer a pain to me. Well, that and the bundled helper tools
for helping me out in the testing task, which I&amp;#39;ll explore more in-depth in this article.&lt;/p&gt;
&lt;h3&gt;Why splitting a spec in multiple files?&lt;/h3&gt;
&lt;p&gt;After writing some specs you can end up with a huge file when writing an integration testing
for an application. There will be lots of &amp;quot;describes&amp;quot;/contexts and I&amp;#39;d rather see them split
in multiple files for better organization and maintainability. But this is just a suggestion,
feel free to use regular &amp;quot;class&amp;quot; constructions in CoffeeScript and put everything in a single
file if you prefer.&lt;/p&gt;
&lt;h3&gt;What about full integration tests?&lt;/h3&gt;
&lt;p&gt;The integration tests I&amp;#39;ll be talking about in this article will use a mocked fake server that
will simulate replying to AJAX requests. This will only work for requests using jQuery.ajax
(or getJSON/post) which is stubbed by the excelent &lt;a href=&quot;http://sinonjs.org/&quot;&gt;SinonJS&lt;/a&gt; written
by my friend &lt;a href=&quot;http://cjohansen.no/&quot;&gt;Christian Johansen&lt;/a&gt; from Gitorious fame.&lt;/p&gt;
&lt;p&gt;This will allow the techniques presented in this article to be used with whatever web framework
you can think of. Another advantage is that it will run pretty fast by mocking the server-side
responses.&lt;/p&gt;
&lt;p&gt;Having said that, if you really want to write full integration tests, like with Capybara, this
should be pretty easy to achieve if your application is written in Rails. It is just a matter
of mounting the spec runner in some route like &amp;#39;/oojspec&amp;#39; for your test environment. Please
leave some comment if you want some detailed instructions on how to do that, but be aware that
you won&amp;#39;t be able to write Ruby code from your JavaScript specs, like filling some initial data
in the database through some beforeEach calls... You&amp;#39;d need to add some extra test-only routes
for helping you with that.&lt;/p&gt;
&lt;h2&gt;Enough with the small talk! Get me right into the subject!&lt;/h2&gt;
&lt;p&gt;Okay, okay, calm down :)&lt;/p&gt;
&lt;h3&gt;Installing instructions&lt;/h3&gt;
&lt;h4&gt;Non-Rails applications&lt;/h4&gt;
&lt;p&gt;You&amp;#39;ll need a minimal Rails application in some of your application sub-directory.&lt;/p&gt;
&lt;p&gt;Here are the instructions for doing so (You&amp;#39;ll need Ruby 1.9 and RubyGems installed):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;gem install bundler; gem install rake;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rosenfeld/oojs_assets_enabler&quot;&gt;Oojs Assets Enabler&lt;/a&gt; -
just clone it to some first-level subdirectory;&lt;/li&gt;
&lt;li&gt;Run &amp;quot;bundle&amp;quot; from this subdirectory;&lt;/li&gt;
&lt;li&gt;Optionally symlink the Rakefile to your root directory;&lt;/li&gt;
&lt;li&gt;Run &amp;quot;rake oojs:spec_helper&amp;quot; to create a sample spec_helper.js.coffee;&lt;/li&gt;
&lt;li&gt;Run &amp;quot;rake oojs:spec -- --name=shopping_cart&amp;quot; to create a sample spec;&lt;/li&gt;
&lt;li&gt;Run &amp;quot;rake oojs:serve&amp;quot; to start the server;&lt;/li&gt;
&lt;li&gt;navigate to &lt;a href=&quot;http://localhost:5000&quot;&gt;http://localhost:5000&lt;/a&gt; to see your specs passing.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Rails applications&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Add the &amp;#39;oojs&amp;#39; gem to your Gemfile and run &amp;quot;bundle&amp;quot;;&lt;/li&gt;
&lt;li&gt;rails g coffee:assets shopping_cart; # or js:assets if you prefer&lt;/li&gt;
&lt;li&gt;rails g oojs:asset_helper;&lt;/li&gt;
&lt;li&gt;rails g oojs:asset shopping_cart;&lt;/li&gt;
&lt;li&gt;rake sandbox_assets:serve;&lt;/li&gt;
&lt;li&gt;navigate to &lt;a href=&quot;http://localhost:5000&quot;&gt;http://localhost:5000&lt;/a&gt; and see your specs passing.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Organizing your tests/specs&lt;/h3&gt;
&lt;p&gt;The specs go to &amp;quot;spec/javascripts/*_spec.js(.coffee)&amp;quot;.
They usually &amp;quot;=require spec_helpers&amp;quot; in the first line.&lt;/p&gt;
&lt;p&gt;You&amp;#39;re encouraged to split your spec class in several files. Just see the example specs created
by the bundled generators.&lt;/p&gt;
&lt;p&gt;If you run the spec_helper generator and then run &amp;quot;rails g oojs:asset shopping_cart&amp;quot; (or
&amp;quot;rake oojs:spec -- --name=shopping_cart&amp;quot; for non Rails applications), these files will
be created:&lt;/p&gt;
&lt;p&gt;spec/javascripts/spec_helper.js.coffee:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;# =require application
# =require modules
# =require jquery
# =require oojspec_helpers
# #require jquery.ba-bbq # uncomment for enabling $.deparam()
#
# Put your common spec code here.
# Then put &amp;quot;# =require spec_helper&amp;quot; in your specs headers.b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#39;ll need to remove the first &amp;quot;# =require application&amp;quot; line if your application doesn&amp;#39;t have
an application.js(.coffee) file in the assets path. All other dependencies are provided by
the oojs gem.&lt;/p&gt;
&lt;p&gt;spec/javascripts/shopping_cart_spec.js.coffee:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;# =require spec_helper
# =require_tree ./shopping_cart

oojspec.describe &amp;#39;ShoppingCart&amp;#39;, new specs.ShoppingCartSpec
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;spec/javascripts/shopping_cart/main.js.coffee:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;extendClass &amp;#39;specs.ShoppingCartSpec&amp;#39;, (spec)-&amp;gt;
  initialize: -&amp;gt;
    @createFakeServer()
    @extend this, new specs.oojspec.AjaxHelpers(@fakeServer)

  runSpecs: -&amp;gt;
    @beforeAll -&amp;gt; @fakeServer.start()
    @afterAll -&amp;gt; @fakeServer.stop()
    @before -&amp;gt; @fakeServer.ignoreAllRequests()

    @it &amp;#39;passes&amp;#39;, -&amp;gt;
      @expect(@fakeServer).toBeDefined()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Feel free to add as many files you want inside the spec/javascripts/shopping_cart/ directory.&lt;/p&gt;
&lt;p&gt;spec/javascripts/shopping_cart_spec/fake_server.js.coffee:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;# =require fake_ajax_server

createProducts = -&amp;gt; [
  {id: 1, name: &amp;#39;One&amp;#39;}
  {id: 2, name: &amp;#39;Two&amp;#39;}
]

extendClass &amp;#39;specs.ShoppingCartSpec&amp;#39;, -&amp;gt;
  createFakeServer: -&amp;gt;
    @fakeServer = new FakeAjaxServer (url, settings)-&amp;gt;
      if settings then settings.url = url else settings = url
      handled = false
      switch settings.dataType
        when &amp;#39;json&amp;#39; then switch settings.type
          when &amp;#39;get&amp;#39; then switch settings.url
            when &amp;#39;/products&amp;#39; then handled = true; settings.success createProducts()
#         when &amp;#39;post&amp;#39; then switch settings.url
#           when ...
#       when undefined then switch settings.type
#         when &amp;#39;get&amp;#39; then switch settings.url
#           when ...
#         when &amp;#39;post&amp;#39; then switch settings.url
#           when ...
      return if handled
      console.log arguments
      throw &amp;quot;Unexpected AJAX call: #{settings.url}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;AJAX calls&lt;/h2&gt;
&lt;p&gt;Whenever your application issue an AJAX request, and that is handled by your fake server, you&amp;#39;ll
need to decide what to do in your specs. For example, if you click a button and wants to wait
for an ajaxRequest to complete, and then process the request, do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;  @it &amp;#39;asks for products when clicking on Products button&amp;#39;, -&amp;gt;
    $(&amp;#39;#products-button&amp;#39;).click()
    @waitsForAjaxRequest()
    @runs -&amp;gt;
      @nextRequest &amp;#39;/products&amp;#39;, &amp;#39;get&amp;#39;, &amp;#39;json&amp;#39; # won&amp;#39;t pass if such a request wasn&amp;#39;t issued
      @expect($(&amp;#39;ul#products li:contains(One)&amp;#39;)).toExist()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Take a look at &lt;a href=&quot;https://github.com/rosenfeld/oojs/blob/master/lib/assets/javascripts/oojspec_helpers/ajax_spec_helpers.js.coffee&quot;&gt;ajax_spec_helpers.js.coffee&lt;/a&gt;
for a list of useful available helpers.&lt;/p&gt;
&lt;p&gt;Also take a look at &lt;a href=&quot;https://github.com/rosenfeld/oojs/blob/master/lib/assets/javascripts/oojspec_helpers/oojspec-jquery.js.coffee#L29&quot;&gt;oojspec-jquery.js.coffee&lt;/a&gt;
for a list of additional matchers for usage with jQuery objects.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There is a lot more to discuss but this article has already taken me a lot of time. I&amp;#39;m intending
to write another article creating a test suite for an existent sample application to further
demonstrate its capabilities.&lt;/p&gt;
&lt;p&gt;Feel free to leave any questions or suggestions in the comments so that we can improve those
techniques even more.&lt;/p&gt;
&lt;p&gt;Happy client-side coding :)&lt;/p&gt;
</content:encoded></item><item><title>Getting started with Sequel in Rails</title><link>https://rosenfeld.page/articles/2012_04_18_getting_started_with_sequel_in_rails/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2012_04_18_getting_started_with_sequel_in_rails/</guid><pubDate>Wed, 18 Apr 2012 15:35:00 GMT</pubDate><content:encoded>&lt;h1&gt;Why Sequel?&lt;/h1&gt;
&lt;p&gt;In short, I feel it is better designed than ActiveRecord and makes some non-trivial queries much
easier to implement and read. Detailed information can be found &lt;a href=&quot;/en/articles/ruby-rails/2013-12-18-sequel-is-awesome-and-much-better-than-activerecord&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;How to use Sequel models?&lt;/h1&gt;
&lt;p&gt;I didn&amp;#39;t create any generator or gem for my application. It is just pretty simple to setup your environment.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add &amp;quot;gem &amp;#39;sequel&amp;#39;&amp;quot; to your Gemfile&lt;/li&gt;
&lt;li&gt;Create an initializer, like config/initializers/setup-sequel.rb (see example below)&lt;/li&gt;
&lt;li&gt;Create your models (see example below)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# config/initializers/setup-sequel.rb
c = ActiveRecord::Base.configurations[Rails.env]
c[&amp;#39;adapter&amp;#39;] = &amp;#39;postgres&amp;#39; if c[&amp;#39;adapter&amp;#39;] == &amp;#39;postgresql&amp;#39;
c[&amp;#39;user&amp;#39;] = c.delete &amp;#39;username&amp;#39;
c[&amp;#39;logger&amp;#39;] = [Rails.logger, Logger.new(&amp;quot;log/#{Rails.env}_db.log&amp;quot;)]
c[&amp;#39;logger&amp;#39;] &amp;lt;&amp;lt; Logger.new(STDOUT) if Rails.env.development?
DB = Sequel::Model.db = Sequel.connect c
Sequel::Model.db.sql_log_level = Rails.application.config.log_level || :info

if ARGV.any?{|p| p =~ /(--sandbox|-s)/}
  # do everything inside a transaction when using rails c --sandbox (or -s)
  DB.pool.after_connect = proc do |conn|
    DB.send(:add_transaction, conn, {})
    DB.send(:begin_transaction, conn, {})
  end
end

# Sequel::Model.plugin :active_model
# Sequel::Model.plugin :validation_helpers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can enable the &lt;a href=&quot;http://sequel.rubyforge.org/plugins.html&quot;&gt;available plugins&lt;/a&gt; directly in the initializer or in a per-class basis.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re using &lt;a href=&quot;https://github.com/thoughtbot/factory_girl&quot;&gt;FactoryGirl&lt;/a&gt;, it requires the model classes to respond to &amp;#39;save!&amp;#39;,
so you can add this to your initializer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;module Sequel::Plugins::FactoryGirlSupport
  module InstanceMethods
    def save!
      save_changes raise_on_save_failure: true
    end
  end
end
Sequel::Model.plugin Sequel::Plugins::FactoryGirlSupport # or plugin :factory_girl_support
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, create your models:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# app/models/user.rb
class User &amp;lt; Sequel::Model
  # do whatever you want here
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#39;re used to ActiveRecord you can take a look at &lt;a href=&quot;http://sequel.rubyforge.org/rdoc/files/doc/active_record_rdoc.html&quot;&gt;Sequel for ActiveRecord Users&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Devise&lt;/h2&gt;
&lt;p&gt;If you want to use your Sequel model as a Devise authentication class, please take a look at the &lt;a href=&quot;https://github.com/rosenfeld/sequel-devise&quot;&gt;sequel-devise gem&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In short, just append &amp;quot;gem &amp;#39;sequel-devise&amp;#39;&amp;quot; to your Gemfile (you&amp;#39;ll also need the &amp;#39;devise&amp;#39; gem if you&amp;#39;re starting from scratch).&lt;/p&gt;
&lt;p&gt;Then, enable your User class to be compatible with Devise. If you want to keep your current User class while you&amp;#39;re giving this a try,
just put it in another namespace, as in the example below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# app/models/sq/user.rb
module SQ
  class User &amp;lt; Sequel::Model
    plugin :devise
    devise :database_authenticatable
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, in your routes, if you&amp;#39;re using this namespaced User class, you&amp;#39;ll need to adapt your devise_for statement to something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# config/routes.rb
devise_for :users, class_name: &amp;#39;SQ::User&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;RSpec&lt;/h2&gt;
&lt;p&gt;For running your examples inside database transactions, you can add this to your spec_helper.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;  # setup transactional factory for Sequel
  config.around(:each) do |example|
    DB.transaction do
      example.run
      raise Sequel::Error::Rollback
    end
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Have fun&lt;/h1&gt;
&lt;p&gt;Feel free to leave any questions in the comments or to report any bugs to the sequel-devise gem.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re like me, you&amp;#39;ll enjoy Sequel way better than ActiveRecord.&lt;/p&gt;
</content:encoded></item><item><title>MySql localhost behavior is totally insane</title><link>https://rosenfeld.page/articles/2012_03_26_mysql_localhost_behavior_is_totally_insane/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2012_03_26_mysql_localhost_behavior_is_totally_insane/</guid><pubDate>Mon, 26 Mar 2012 22:40:00 GMT</pubDate><content:encoded>&lt;p&gt;I always have this issue so I found it would be better to document it for myself.&lt;/p&gt;
&lt;p&gt;I never really liked MySql, preferring PostgreSQL instead for multiple reasons, but that is
not what this article is about. While I don&amp;#39;t migrate the current database to PostgreSQL
(everything is already set up, just waiting for permission for doing so), I&amp;#39;ll probably have
this issue many more times.&lt;/p&gt;
&lt;p&gt;I have some port redirects to my application production database servers. And I always try
to access using this command line (or through some library API, it doesn&amp;#39;t make any difference):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;mysql -h localhost -P 3307 -u my_user -p my_database_name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem is that I succeed on doing that, but I&amp;#39;m actually using my local database using sockets. WTF?!&lt;/p&gt;
&lt;p&gt;Since I have the same users and passwords in my local database, it doesn&amp;#39;t complain, but it completely ignores
the -P (--port) argument and I think I&amp;#39;m accessing the right database. There are two fixes for that. The most
simple one and that will also work in my software configurations is to use 127.0.0.1 instead of localhost.&lt;/p&gt;
&lt;p&gt;For the command line, you can use also add the --protocol=tcp argument:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;mysql --protocol=tcp -h localhost -P 3307 -u my_user -p my_database_name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I don&amp;#39;t understand why the protocol isn&amp;#39;t set to TCP automatically when you specify a TCP port in the
program arguments! This is just dumb! And worse than that is to find out that the
&lt;a href=&quot;http://bugs.mysql.com/bug.php?id=31577&quot;&gt;state for this bug is &amp;quot;Not a bug&amp;quot;&lt;/a&gt;. I really hate MySql.&lt;/p&gt;
</content:encoded></item><item><title>How NokoGiri and JRuby saved my week</title><link>https://rosenfeld.page/articles/ruby-rails/2012_03_04_how_nokogiri_and_jruby_saved_my_week/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2012_03_04_how_nokogiri_and_jruby_saved_my_week/</guid><pubDate>Sun, 04 Mar 2012 12:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#39;d like to share some experiences I had this week trying to parse some HTML with Groovy.&lt;/p&gt;
&lt;p&gt;Then, I&amp;#39;ll explain how it was better done with JRuby and it was also finished much faster too.&lt;/p&gt;
&lt;p&gt;This week I had to extract some references from some HTML documents and store them to the database.&lt;/p&gt;
&lt;p&gt;This is the spec of what I wanted to implement in MiniTest specs written in Ruby:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# encoding: utf-8
require &amp;#39;minitest/autorun&amp;#39;
require_relative &amp;#39;../lib/references_extractor&amp;#39;

describe ReferencesExtractor do
  def example
    %Q{
      &amp;lt;div cid=1&amp;gt;
        &amp;lt;empty cid=11&amp;gt;
        &amp;lt;/empty&amp;gt;
        some text
        &amp;lt;div cid=12&amp;gt;
          &amp;lt;div cid=121&amp;gt;
            &amp;lt;empty /&amp;gt;&amp;lt;another&amp;gt;&amp;lt;/another&amp;gt;
            &amp;lt;p cid=1211&amp;gt;First paragraph.&amp;lt;/p&amp;gt;
            &amp;lt;p cid=1212&amp;gt;Second paragraph.&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;p cid=122&amp;gt;Another pa&amp;lt;b&amp;gt;ra&amp;lt;/b&amp;gt;graph.&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    }
  end

  it &amp;quot;extract references from example&amp;quot; do
    return
    extractor = ReferencesExtractor.new example
    {
      [&amp;#39;1&amp;#39;] =&amp;gt; {&amp;#39;1&amp;#39; =&amp;gt; &amp;quot;some text First paragraph. Second paragraph. Another paragraph.&amp;quot;},
      [&amp;#39;1211&amp;#39;, &amp;#39;1212&amp;#39;, &amp;#39;11&amp;#39;] =&amp;gt; {&amp;#39;121&amp;#39; =&amp;gt; &amp;quot;First paragraph. Second paragraph.&amp;quot;},
      [&amp;#39;1211&amp;#39;, &amp;#39;1212&amp;#39;, &amp;#39;122&amp;#39;] =&amp;gt; {&amp;#39;12&amp;#39; =&amp;gt; &amp;quot;First paragraph. Second paragraph. Another paragraph.&amp;quot;},
      [&amp;#39;12&amp;#39;, &amp;#39;1212&amp;#39;]          =&amp;gt; {&amp;#39;12&amp;#39; =&amp;gt; &amp;quot;First paragraph. Second paragraph. Another paragraph.&amp;quot;},
      [&amp;#39;1212&amp;#39;, &amp;#39;122&amp;#39;] =&amp;gt; {&amp;#39;1212&amp;#39; =&amp;gt; &amp;quot;Second paragraph.&amp;quot;, &amp;#39;122&amp;#39; =&amp;gt; &amp;quot;Another paragraph.&amp;quot;},
    }.each {|cids, expected| extractor.get_references_texts(cids).must_equal(expected) }
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had a similar test written using JUnit, with a small change to make it more easy to implement but
I&amp;#39;ll discuss it later on in this article. Let me just explain this situation better.&lt;/p&gt;
&lt;p&gt;Don&amp;#39;t ask me what &amp;quot;cid&amp;quot; means as I wasn&amp;#39;t the one to name this attribute, but I guess it is &amp;quot;c...&amp;quot; id,
although I have no clue what is &amp;quot;c...&amp;quot; all about. It was already called this way when I started working
on this project and I&amp;#39;m the sole developer of this project right now after lots of other developers
having worked on it before me.&lt;/p&gt;
&lt;p&gt;Part of the application I maintain has to deal with documents obtained from
&lt;a href=&quot;http://www.sec.gov/edgar.shtml&quot;&gt;Edgar filings&lt;/a&gt;. Then a processing is made to each HTML tag so that they&amp;#39;re
given sequential unique numbers in the &amp;quot;cid&amp;quot; attribute. Someone will then be able to review the documents
and highlight certain parts of it by clicking on the elements in the page. So the database has a reference
to a document and a cid list, like &amp;quot;1000,1029,1030&amp;quot; will all elements that should be highlighted. This was
stored exactly this way as a string in a database column.&lt;/p&gt;
&lt;p&gt;But some weeks ago I was requested to export the contents of some highlighted references to an Excel
spreadsheet and this is somewhat more complex than it looks like. With jQuery, it would be equivalent to
&amp;quot;$(&amp;#39;[cid=12]&amp;#39;).text()&amp;quot;.&lt;/p&gt;
&lt;p&gt;For performance reasons in the search interface I had to import all references from over 3,000 documents to
the database. For the new references, I&amp;#39;ll do the processing with jQuery and send it already formatted to
the server, but I need to do the initial import and doing the batch processing in the client-side would be
painfully slow for this case.&lt;/p&gt;
&lt;p&gt;But getting the correct output in the server-side is not that simple. For example, for those documents,
there is no CSS involved, making it simpler to deal with. So &amp;quot;&amp;lt;div&amp;gt;some t&amp;lt;div&amp;gt;ex&amp;lt;/div&amp;gt;t&amp;lt;/div&amp;gt;&amp;quot;
should be stored as &amp;quot;some t ex t&amp;quot; while &amp;quot;&amp;lt;div&amp;gt;some t&amp;lt;span&amp;gt;ex&amp;lt;/span&amp;gt;t&amp;quot; should be stored as
&amp;quot;some text&amp;quot;. Since this requires a deeper understanding of HTML semantics, I decided to simplify it while
dealing with Groovy and assume all elements as being block-level elements while parsing the fixed HTML as XML.&lt;/p&gt;
&lt;h2&gt;The Groovy solution&lt;/h2&gt;
&lt;p&gt;Doing that in Groovy took me a full week specially due to lack of documentation of
&lt;a href=&quot;http://groovy.codehaus.org/api/groovy/util/XmlParser.html&quot;&gt;XmlParser&lt;/a&gt; and
&lt;a href=&quot;http://groovy.codehaus.org/api/groovy/util/XmlSlurper.html&quot;&gt;XmlSlurper&lt;/a&gt; Groovy classes.&lt;/p&gt;
&lt;p&gt;First, I had no clue which one to choose. As they had a similar interface I decided to start with XmlParser,
and then change to XmlSlurper when it was finished to compare the performance between them.&lt;/p&gt;
&lt;p&gt;I couldn&amp;#39;t find any methods for searching for some XPATH or CSS expression. When you write
&amp;quot;new XmlParser().parseText(xmlContent)&amp;quot;, you get a &lt;a href=&quot;http://groovy.codehaus.org/api/groovy/util/Node.html&quot;&gt;Node&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;XmlParser is not an HTML parser, so the XML content should be well formed, then you need to use some library
like &lt;a href=&quot;http://nekohtml.sourceforge.net/&quot;&gt;NekoHTML&lt;/a&gt; or &lt;a href=&quot;http://ccil.org/~cowan/XML/tagsoup/&quot;&gt;TagSoup&lt;/a&gt;.
Then you would use it like
&amp;quot;new XmlParser(new &lt;a href=&quot;http://www.jarvana.com/jarvana/view/org/ccil/cowan/tagsoup/tagsoup/1.2.1/tagsoup-1.2.1-javadoc.jar!/org/ccil/cowan/tagsoup/Parser.html&quot;&gt;Parser&lt;/a&gt;()).parseText(xmlContent)&amp;quot;
That&amp;#39;s ok, but if you want to play with it and don&amp;#39;t know Groovy enough for dealing with Gradle and Maven
dependencies, just use a valid XML as an example. &lt;/p&gt;
&lt;p&gt;Since I couldn&amp;#39;t find a search-like method for Node, I had to look for node &amp;#39;[cid=12]&amp;#39; with something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;xmlContent = &amp;#39;&amp;lt;div cid=&amp;quot;12&amp;quot;&amp;gt; some text &amp;lt;span cid=&amp;quot;13&amp;quot;&amp;gt; as an example &amp;lt;/span&amp;gt;.&amp;lt;/div&amp;gt;&amp;#39;
root = new XmlParser().parseText(xmlContent)
node = root.depthFirst().find { it.@cid == &amp;#39;12&amp;#39; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling &amp;quot;node.text()&amp;quot; would yield to &amp;#39;some text.&amp;#39; and calling &amp;quot;node.children()&amp;quot; would yield to
[&amp;#39;some text&amp;#39;, spanNode, &amp;#39;.&amp;#39;], which means it ignores white spaces, so it is of no usage to me.&lt;/p&gt;
&lt;p&gt;So, I tried XmlSlurper. In this case, node.text() yields to &amp;#39; some text  as an example .&amp;#39;. Great
for this example, but when applied to node with cid 12 in the MiniTest example above, it would
yield to &amp;#39;First paragraph.Second paragraph.Another paragraph.&amp;#39; ignoring all white spaces,
so I couldn&amp;#39;t use this.  &lt;/p&gt;
&lt;p&gt;But after searching a lot, I figured out that there was a class that would convert some node back
to XML including all original white spaces, so it should be possible. Then I tried to get the text by myself.&lt;/p&gt;
&lt;p&gt;&amp;quot;node.children()&amp;quot; returned [spanNodeChildInstance], ignoring the text nodes, so I was out of luck and
had to dig into its source code. Finally after some hours digging the source-code I found what I
was looking for: &amp;quot;node[0].children()&amp;quot; returning [&amp;#39; some text &amp;#39;, spanNode, &amp;#39;.&amp;#39;].&lt;/p&gt;
&lt;p&gt;It took a while before I could get this to work, but I wasn&amp;#39;t finished with it. I would have to
navigate the XML tree for getting the final processed text. Look at the MiniTest example again
and you&amp;#39;ll see that I needed to get node with cid 12 as equivalent to the cid list [1211, 1212, 122].&lt;/p&gt;
&lt;p&gt;So, one of the features I needed is to look for the first node ancestral having a cid, so that I
could try it to see if it was a possible node. It happens that it was not that simple as while
traversing the parents maybe I couldn&amp;#39;t find any parent node with a cid. So, how could I check
that I&amp;#39;ve reached the root node?&lt;/p&gt;
&lt;p&gt;With XmlSlurper, when you call rootNode.parent() you&amp;#39;ll get rootNode. So, I tried something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;parent = node.parent()
while (!parent.@cid &amp;amp;&amp;amp; parent != parent.parent()) parent = parent.parent()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the problem is that the comparison is made by string, so I have no real way to see if I have reached
the parent. So, my solution was to check for &amp;quot;node.name() != &amp;#39;html&amp;#39;&amp;quot; in this case. This is really
a bad API design. Maybe root.parent() could return null. Also, I should be able to compare a node instead
of its text.&lt;/p&gt;
&lt;p&gt;After several days, in the end of last Thursday I could get a &amp;quot;working&amp;quot; version of a similar JUnit
test passing with an implementation in Groovy. But as I wasn&amp;#39;t using really an HTML parser, but an XML
one, it means that I couldn&amp;#39;t process white-spaces correctly for in-line blocks.&lt;/p&gt;
&lt;h2&gt;NokoGiri&lt;/h2&gt;
&lt;p&gt;Then, on Friday morning I was curious how I could parse HTML with Ruby, as I never did it before.
That was when I got my first smile that morning when I read this from Aaron Patterson documentation of
NokoGiri:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;XML is like violence - if it doesn’t solve your problems, you are not using enough of it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The smile got even bigger when I tried this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;require &amp;#39;nokogiri&amp;#39;
Nokogiri::HTML(&amp;#39;&amp;lt;div&amp;gt;Some &amp;lt;span&amp;gt;Te&amp;lt;b&amp;gt;x&amp;lt;/b&amp;gt;t&amp;lt;/span&amp;gt;.&amp;#39;).text == &amp;#39;Some Text.&amp;#39; # true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The smile has shrunk a bit when I realized that I would get the same result if I replaced the
inline &amp;quot;b&amp;quot; block element with a &amp;quot;div&amp;quot;. But that is ok, it was already good enough.&lt;/p&gt;
&lt;p&gt;Other than the &amp;quot;text&amp;quot; method being more useful than the one used by XmlSlurper (new-lines are
treated differently), navigating the XML tree is also much easier with NokoGiri. But I still couldn&amp;#39;t
find a good way of finding out if some node was a root one, as calling &amp;quot;root.parent&amp;quot; would raise
an exception. Fortunately, as NokoGiri supports XPATH, I didn&amp;#39;t need to do this manual traversing
and this wasn&amp;#39;t an issue to my specific needs.&lt;/p&gt;
&lt;p&gt;But there was a remaining issue. It performed very badly when compared to the Groovy version, about 4
times slower. Looking at my CPU usage statistics it was obvious to me that it wasn&amp;#39;t using all my CPU
power, as in the Groovy version. It didn&amp;#39;t matter how much threads I used with CRuby, each processor wouldn&amp;#39;t
be over 20% of the available capacity.&lt;/p&gt;
&lt;h2&gt;JRuby to the rescue&lt;/h2&gt;
&lt;p&gt;It is a shame that the Java API actually has a better API than Ruby for dealing with a pool of threads.
It is called the Executors framework. As I couldn&amp;#39;t find something like this in the Ruby standard library,
I tried a Ruby gem called &lt;a href=&quot;https://github.com/appoxy/concur/&quot;&gt;Concur&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I didn&amp;#39;t investigate if the performance issues were caused by Concur implementation or the CRuby one,
but I decided to give JRuby or Rubinius a try. As I already had JRuby available, I tried it first and as
the results were about the same as the Groovy version, I didn&amp;#39;t bother to check Rubinius.&lt;/p&gt;
&lt;p&gt;With JRuby I could use the Java Executors framework just like in Groovy and I could see all my 6 cores
above 90% all the time my 10 threads have been working for importing over 3,000 documents. Unfortunately
my actual servers are much slower than my computer and it took more than 4 hours in the staging server
when it took about an hour and a half in my computer. The CRuby version would probably take more than 4 hours
in my computer, which means it could take almost a full day in the staging and production servers.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I must explain that I haven&amp;#39;t tried using Ruby first because I would be able to take advantage
of my models being already mapped by the Grails application, so I wouldn&amp;#39;t have to deal with database
set-up and would be allowed to have all my code in a single language. Of course, if I knew
beforehand all the pain that it would be coding this in Groovy, I would have already done this in Ruby
from the beginning. And the Ruby version was a bit better than my previous attempt with Groovy with regards
to some corner cases including new-lines processing.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m very grateful for Aaron tendelove Paterson and Charles Nutter for their awesome work on Ruby,
NokoGiri and JRuby. Thanks to them I could get my work done very fast in an elegant way, saving
my week of frustration with Groovy.&lt;/p&gt;
</content:encoded></item><item><title>Should we move forward or remain backward compatible?</title><link>https://rosenfeld.page/articles/ruby-rails/2012_03_04_should_we_move_forward_or_remain_backward_compatible/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2012_03_04_should_we_move_forward_or_remain_backward_compatible/</guid><pubDate>Sun, 04 Mar 2012 12:30:00 GMT</pubDate><content:encoded>&lt;p&gt;This is just an article&amp;#39;s title, not really a question with a right answer.&lt;/p&gt;
&lt;p&gt;It is not always possible to both move forward and remain compatible with legacy code.&lt;/p&gt;
&lt;p&gt;Usually, when a project starts there is no legacy code and every change is welcomed.
Later on, when the project grows and the user&amp;#39;s code base gets bigger, some people will
start complaining about incompatible changes because they&amp;#39;ll have to spend some time
changing their code base when they decide to upgrade to a newer version.&lt;/p&gt;
&lt;p&gt;When this time comes, the project has to make a decision. It should either keep moving
forward and fixing badly designed API when they realize there is a better way of doing
things or they should accept that an API change can be very painful for their
framework/library users and decide to keep on with the bad API. Java definitely opted
for the latter.&lt;/p&gt;
&lt;h2&gt;The Rails case&lt;/h2&gt;
&lt;p&gt;In the last weeks, I&amp;#39;ve been reading
&lt;a href=&quot;http://gilesbowkett.blogspot.com/2012/02/rails-went-off-rails-why-im-rebuilding.html&quot;&gt;some&lt;/a&gt;
&lt;a href=&quot;http://merbist.com/2012/02/29/learning-from-rails-failures/&quot;&gt;articles&lt;/a&gt;
complaining about Rails changing its API in incompatible ways too fast.&lt;/p&gt;
&lt;p&gt;They&amp;#39;re not alone and I&amp;#39;ve seen complaints about this from several other people. In the
other side I&amp;#39;m constantly refactoring my own code base and I appreciate Rails doing the
same. In the case of libraries and framewoks, when we&amp;#39;re refactoring code, sometimes we
come to the conclusion that some API should be better written even if it breaks old software.
And I&amp;#39;m also not alone in thinking this way.&lt;/p&gt;
&lt;p&gt;Unfortunately, I couldn&amp;#39;t find an employer to pay me to work with Rails as much as I do as a
Grails/Groovy/Java developer for the last 3 years. And that is really a pain with regards
to API, stability and user experience. I don&amp;#39;t remember complaining about anything in Ruby
or Rails that I really missed since internationalization support was added to Rails in
version 2.&lt;/p&gt;
&lt;h2&gt;The Groovy / Java case&lt;/h2&gt;
&lt;p&gt;This section has grown too fast, so I decided to split it in another article entitled
&lt;a href=&quot;2012-03-04-how-nokogiri-and-jruby-saved-my-week&quot;&gt;How NokoGiri and JRuby saved my week&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You don&amp;#39;t have to read the entire article if you&amp;#39;re not curious enough, but the Groovy
XML parsers API was so badly designed and documented that I could finish the logic with Ruby and
NokoGiri in about 2 hours (with tests and setup included) while I spent the entire week
trying to do the same in Groovy.&lt;/p&gt;
&lt;p&gt;And the result in Ruby would take about the same time for the import to complete.
I had to dig into Groovy&amp;#39;s source code due to lack of documentation and do lots of experiments
to understand how things worked.&lt;/p&gt;
&lt;p&gt;You can fix documentation issues without changing the API, but you can&amp;#39;t fix design issues
with Groovy parsers without changing its API. So, is it worth keeping the API just for being
backward-compatible and make XML parsing a pain to work with in Groovy?&lt;/p&gt;
&lt;h2&gt;Then what?&lt;/h2&gt;
&lt;p&gt;There is not a better approach to take when you decide for remaining backward compatible or
keep forward. So, each project will adopt some philosophy and you need to know its philosophy
before adopting it or not.&lt;/p&gt;
&lt;p&gt;If you prefer API stability over consistency and easy of use, you should choose something like
Java, C++, Perl, PHP or Grails. You shouldn&amp;#39;t be really considering Rails.&lt;/p&gt;
&lt;p&gt;In the other hand, if you like to be on the edge, then Rails is exactly the way to go.&lt;/p&gt;
&lt;p&gt;Which one to choose will basically depend on these questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do you have a good test coverage of your code base?&lt;/li&gt;
&lt;li&gt;Do you have to respond really fast to changes?&lt;/li&gt;
&lt;li&gt;Will your code hardly change after it is finished?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you answered &amp;quot;yes&amp;quot; to 3, than you should consider a framework that will avoid very hard to
break its API, since no one will constantly maintaining your application to keep up with all
the framework upgrades with fixed security issues, for example.&lt;/p&gt;
&lt;p&gt;In the other hand, if you have answered &amp;quot;yes&amp;quot; to 1 and 2, using a fast pace changing framework
like Rails shouldn&amp;#39;t be an issue. In my case, I don&amp;#39;t write tests for my views as they&amp;#39;re usually
very simple and doesn&amp;#39;t contain logic. So, when Rails changed some rules about when to use
&amp;quot;&amp;lt;%= ... %&amp;gt;&amp;quot; or &amp;quot;&amp;lt;% ... %&amp;gt;&amp;quot;, I had to manually look at all of my views to fix them. And I had to
do that twice between Rails 2 and Rails 3.1, for example because they did change this behavior
back and forward and this is the kind of unnecessary change in my opinion.&lt;/p&gt;
&lt;p&gt;Other changes I had to manually check because I don&amp;#39;t test my views is due the change of the
output of ERB tags being escaped by default. But that is a good change and I&amp;#39;m pretty sure I forgot
to manually escape some of them before the upgrade. So, my application was probably safer
against attacks after the upgrade, so this is a good move even so it took a while for me to
finish the upgrade. There was no easy path for this change.&lt;/p&gt;
&lt;p&gt;But other than that, it was just a matter of making the test suite pass after the upgrade, and
if you valuate code refactoring as much as I do, you&amp;#39;ll be writing tests for all code that could
possibly break in some refactoring.&lt;/p&gt;
&lt;p&gt;And this was a hard issue I have with Grails. I find it too time demanding to write tests for
Grails applications and it was really a pain before Grails 2 was released. It is still not good,
but I can already write most of my unit tests in Grails without much problem.&lt;/p&gt;
&lt;p&gt;So, I would suggest you to answer the above questions first before choosing what web framework to
adopt. It is not right to get a fast moving framework because its API is better designed and then
later in the future ask their maintainers to stop changing because now you have a working application.&lt;/p&gt;
&lt;p&gt;You should know how they work beforehand and accept this when you opt of it.&lt;/p&gt;
</content:encoded></item><item><title>How do Rails and Grails differ?</title><link>https://rosenfeld.page/articles/programming/2012_01_21_how_do_rails_and_grails_differ/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2012_01_21_how_do_rails_and_grails_differ/</guid><pubDate>Sat, 21 Jan 2012 14:45:00 GMT</pubDate><content:encoded>&lt;p&gt;A while ago I&amp;#39;ve written on &lt;a href=&quot;2011-08-07-why-i-prefer-rails-over-grails&quot;&gt;why I prefer Rails over Grails&lt;/a&gt;,
so be aware that this is another biased article.&lt;/p&gt;
&lt;p&gt;That old article is already outdated since Grails 2 was released, and I was asked to update that article. That
was my original idea, but then the comments wouldn&amp;#39;t make sense anymore, so I decided to write another take on
Rails and Grails comparison. But this is a completely entire new article and not just an update to the old one.&lt;/p&gt;
&lt;h2&gt;Misconceptions first&lt;/h2&gt;
&lt;h3&gt;Java is rock solid, while Ruby is not&lt;/h3&gt;
&lt;p&gt;I never understood this statement although I&amp;#39;ve been constantly told this for a long time.&lt;/p&gt;
&lt;p&gt;Both languages were first released in 1995, more than 15 years ago, so why wouldn&amp;#39;t Ruby
be considered as solid as Java?&lt;/p&gt;
&lt;h3&gt;Dynamic languages aren&amp;#39;t reliable&lt;/h3&gt;
&lt;p&gt;I have no idea why some people think that getting some program to compile is any indication that it should work.&lt;/p&gt;
&lt;p&gt;Certainly those people don&amp;#39;t include Kent Beck and Erich Gamma or they wouldn&amp;#39;t have developed JUnit back in 1994,
even before Java 1.0 being publicly released by Sun Microsystems.&lt;/p&gt;
&lt;p&gt;So, as far as you understand that you need automated tests in whatever language you choose, it shouldn&amp;#39;t matter
if the language is a static or a dynamic one.&lt;/p&gt;
&lt;h3&gt;Java written code runs much faster than those written in Ruby&lt;/h3&gt;
&lt;p&gt;How much? No one answers me that question. They think this way: &amp;quot;Java programs are compiled, so they must run faster
then sofware written in any interpreted language&amp;quot;. People should really be worried about how fast they need their
application to be before choosing their framework. If they can&amp;#39;t measure, they can&amp;#39;t compare performance, this is
pretty obvious.&lt;/p&gt;
&lt;p&gt;If you need a web application, you should be able to benchmark for your actual scenario before choosing a language and
web framework. Also, if your application is very JavaScript intensive, it shouldn&amp;#39;t really matter the performance of the
server side for many applications.&lt;/p&gt;
&lt;p&gt;A typical web application will fetch data from some kind of database, do some parameters bindings and generate some
HTML, XML or JSON result. This usually happens really fast on any language or web framework, so you shouldn&amp;#39;t be really
concerned about language performance for web applications. Most performance improvements will be a result of some
design change rather than a language change.&lt;/p&gt;
&lt;p&gt;So, it is more likely that the framework design is more important than the language itself. If some language allows
programmers to easily write better designed code, it is more likely that a framework written in such language
will perform better. You should really be concerned on how fast you can develop your solution with the chosen
framework/language. And I really don&amp;#39;t believe anyone can be as productive in Java as in any other dynamic and
less verbose language.&lt;/p&gt;
&lt;h3&gt;Grails is the only Rails-like framework alternative for the JVM&lt;/h3&gt;
&lt;p&gt;Haven&amp;#39;t you ever heard that you can run Rails in the JVM through JRuby, a Ruby interpreter
written in Java? The Rails test suite goes green on JRuby as well.&lt;/p&gt;
&lt;h2&gt;Too much talk, bro, go straight! So, what are the differences?&lt;/h2&gt;
&lt;h3&gt;Reuse of software vs monolithic&lt;/h3&gt;
&lt;p&gt;Grails is built on top of the well known Spring framework and Hibernate, and integrates to Maven and Ivy.&lt;/p&gt;
&lt;p&gt;Rails was originally considered a monolithic full-stack framework, with very few dependencies on external libraries.
This has changed a lot since the Rails 3 refactoring, but somehow people still see Rails as a monolithic framework.&lt;/p&gt;
&lt;h3&gt;Integration level&lt;/h3&gt;
&lt;p&gt;While both Rails and Grails will reuse external libraries, Rails seems to be more well integrated to them than Grails.&lt;/p&gt;
&lt;p&gt;This is very noticeable in the case of Hibernate integration on GORM, the Grails Object-Relational Mapper (ORM).&lt;/p&gt;
&lt;p&gt;Rails uses by default the ActiveRecord library as their ORM solution, that implements the Active Record pattern in Ruby.&lt;/p&gt;
&lt;p&gt;Hibernate, in the other side, adopted the Data Mapper / Unit of Work (Session) pattern.&lt;/p&gt;
&lt;p&gt;I won&amp;#39;t cover the differences, merits and shortcomings of those patterns as it is out of the scope for this article and
there is plenty of information around the web about them. I&amp;#39;d just like to state that you can opt for the
&lt;a href=&quot;http://datamapper.org/&quot;&gt;DataMapper&lt;/a&gt; library in Ruby if you prefer this pattern.&lt;/p&gt;
&lt;p&gt;The important thing here is to point that Grais will try to hide the Hibernate Session for newcomers to Grails and make
some developers believe it implements the Active Record pattern, since the Data Mapper pattern add complexity for simple
applications. The documentation will only cover Hibernate Sessions after explaining about Domain Modelling. This topic is
so important for avoiding issues with Grails that it should be the first one as it can lead to several unexpected results.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re planning to to use Grails, don&amp;#39;t do that before reading the entire documentation for GORM and this series of 3
articles about &lt;a href=&quot;http://blog.springsource.com/2010/06/23/gorm-gotchas-part-1/&quot;&gt;GORM Gotchas&lt;/a&gt;. This will save a lot of your
time in the future.&lt;/p&gt;
&lt;p&gt;GORM has bad defaults for newcomers and you&amp;#39;ll be surprised by &lt;strong&gt;when&lt;/strong&gt; data is persisted and why you can&amp;#39;t call save()
directly in some GORM instance in a background thread. That is usually the situation where you learn about the Hibernate
Session if you haven&amp;#39;t read the entire documentation before.&lt;/p&gt;
&lt;p&gt;On the other hand I haven&amp;#39;t found a single &amp;quot;gotcha&amp;quot; for the ActiveRecord gem, used by Rails as the default ORM implementation.
Also all libraries used by Rails are very well integrated.&lt;/p&gt;
&lt;h3&gt;Object-Relational Mapping&lt;/h3&gt;
&lt;h3&gt;Automated Testing&lt;/h3&gt;
&lt;h3&gt;Bugs&lt;/h3&gt;
&lt;h3&gt;Community Ecosystem&lt;/h3&gt;
&lt;h3&gt;Framework source code&lt;/h3&gt;
</content:encoded></item><item><title>What did I learn about Code Writing?</title><link>https://rosenfeld.page/articles/programming/2012_01_08_what_did_i_learn_about_code_writing/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2012_01_08_what_did_i_learn_about_code_writing/</guid><pubDate>Sun, 08 Jan 2012 23:57:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#39;ve being coding for about 2 decades now. And still I don&amp;#39;t find it to be an exact science,
as some would like to suppose. Otherwise, they wouldn&amp;#39;t ask you for time estimates on feature
requests or try to use tools like MS Project to manage a software project, as if Gantt charts
could be useful for this kind of project.&lt;/p&gt;
&lt;p&gt;Of course, I can completely understand the reasons for the ones willing to bring such project
management tools to the software world. Good luck to them! But I won&amp;#39;t talk about this subject
in this article as it is too big. I would just like to state that software can be better
understood when compared to sciences like Music or general Arts.&lt;/p&gt;
&lt;p&gt;Both require lots of experience, personal feelings and are hard to estimate conclusion times
since it is almost always something completely new. Although there are some recipes for certain
kinds of music or movies, but then they are no longer art.&lt;/p&gt;
&lt;p&gt;Some time ago I was asked to estimate how long it would take for me to implement a search
system over some HTML documents taken from &lt;a href=&quot;http://www.sec.gov/edgar.shtml&quot;&gt;EDGAR filings&lt;/a&gt;.
I&amp;#39;m pretty sure that this wouldn&amp;#39;t be something new for some of you who have already had
experience with search engines before, but that wasn&amp;#39;t my case definitely. So, I knew I
should research about tools like Lucene for search indexing, but I have never worked with
them before. So how could I estimate this?&lt;/p&gt;
&lt;p&gt;As I started following the tutorials, I thought the main problem was solved in the first 2 days,
but I couldn&amp;#39;t predict that I would spend so much time reading about the configuration files for
Solr, and how search params could be adjusted. There is a lot of stuff to know about and configure
for your needs.&lt;/p&gt;
&lt;p&gt;Particularly, one of the curiosities I&amp;#39;ve noticed is that even if my configuration was set to
enable &lt;em&gt;AND&lt;/em&gt;-like search for all typed terms, if it happens for a user to prepend some word with
a plus (&amp;quot;+&amp;quot;) or minus (&amp;quot;-&amp;quot;), then non-prepended words would become optional. I had enabled the
&lt;a href=&quot;http://wiki.apache.org/solr/DisMax&quot;&gt;DisMax&lt;/a&gt; mode, by the way.&lt;/p&gt;
&lt;h2&gt;The challenge&lt;/h2&gt;
&lt;p&gt;So, I&amp;#39;d like to talk specifically about this specific challenge as it is a good example for
demonstrating some techniques I&amp;#39;ve learned last year after reading &lt;a href=&quot;http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882&quot;&gt;Clean Code&lt;/a&gt;.
Although being very Java-oriented, this book has a few simple rules that can be applied to
every language and be really effective. Just like in Music and Movie Making, Software Writing
is also a science in which there are lots of resources to learn from and that can be used in
a systematic way. Learning those tools and techniques will help developers to deliver more
in less time.&lt;/p&gt;
&lt;p&gt;Developers should invest time on well-written code because they&amp;#39;ll spend most of their time
reading code. So, it makes sense to invest time and money on tools that will make it easier to
browse some code as well as investing some time polishing their code so that they become more
readable too.&lt;/p&gt;
&lt;p&gt;Before talking about those simple rules, I&amp;#39;d like to show you how I might write this code in
my early times. Don&amp;#39;t waste your time trying to understand this code. Then, I&amp;#39;ll show you the
code that I&amp;#39;ve actually written in a couple of hours, exactly as I have estimated before, since
it didn&amp;#39;t have any external dependencies. So, basically, this is the trend:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Transform terms like &amp;#39;some +required -not-allowed &amp;quot;any phrase&amp;quot; id:(10 or 20 or 30)&amp;#39; into
&amp;#39;+some +required -not-allowed +&amp;quot;any phrase&amp;quot; +id:(10 or 20 or 30)&amp;#39;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pretty simple, right? But even software like this can be bug-prone. So, here is a poor
implementation (in Groovy, as I&amp;#39;m a Grails programmer in my current job). Don&amp;#39;t try to really
understand it (more on this later), just take a look at the code (dis)organization. I didn&amp;#39;t
even try to compile it.&lt;/p&gt;
&lt;h2&gt;How not to code&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;class SolrService {
  ...
  private String processQuery(String query) {
    query = query.replaceAll(&amp;#39;#&amp;#39;, &amp;#39;&amp;#39;)
    def expressions = [], matches
    while (matches = query =~ /\([^\(]*?\)/) {
      matches.each { match -&amp;gt;
        expressions &amp;lt;&amp;lt; match
        query = query.replace(match, &amp;quot;#{${expressions.size()}}&amp;quot;.toString())
      }
    }
    (query =~ /\&amp;quot;.*?\&amp;quot;/).each { match -&amp;gt;
      expressions &amp;lt;&amp;lt; match
      query = query.replace(match, &amp;quot;#{${expressions.size()}}&amp;quot;.toString())
    }
    query = query.split(&amp;#39; &amp;#39;).findAll{it}.collect { word -&amp;gt;
      word[0] in [&amp;#39;-&amp;#39;, &amp;#39;+&amp;#39;] ? word : &amp;quot;+${word}&amp;quot;
    }.join(&amp;#39; &amp;#39;)
    def s = expressions.size()
    expressions.reverse().eachWithIndex { expression, i -&amp;gt;
      query = query.replace(&amp;quot;#{${s - i}}&amp;quot;, expression)
    }
  }

  def search(query) {
    query = processQuery(query)
    ...
    return solrServer.request(new SolrQuery(query))
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, I&amp;#39;ll agree that for this specific case, the code may be not that bad, but although &lt;em&gt;processQuery&lt;/em&gt; is not
that big, you&amp;#39;ll need some time for figuring it out what is happened if you&amp;#39;re required to modify this method.&lt;/p&gt;
&lt;p&gt;Also, looking at it, could you be sure it will work for all cases? Or could you tell me what is the reason for
some specific line? What is this code protected from? How comfortable would you be if you were to modify this code?
How would you write automated tests for &lt;em&gt;processQuery&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Also, as the logic gets more complex, coding this way could led to some messy code like the one I&amp;#39;ve just taken
from a &lt;a href=&quot;https://github.com/grails/grails-core/blob/master/grails-hibernate/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java&quot;&gt;file in the project that integrates Hibernate to Grails&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;// grails-core/grails-hibernate/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java
// ...
@SuppressWarnings(&amp;quot;rawtypes&amp;quot;)
@Override
public Object invokeMethod(String name, Object obj) {
    Object[] args = obj.getClass().isArray() ? (Object[])obj : new Object[]{obj};

    if (paginationEnabledList &amp;amp;&amp;amp; SET_RESULT_TRANSFORMER_CALL.equals(name) &amp;amp;&amp;amp; args.length == 1 &amp;amp;&amp;amp;
            args[0] instanceof ResultTransformer) {
        resultTransformer = (ResultTransformer) args[0];
        return null;
    }

    if (isCriteriaConstructionMethod(name, args)) {
        if (criteria != null) {
            throwRuntimeException(new IllegalArgumentException(&amp;quot;call to [&amp;quot; + name + &amp;quot;] not supported here&amp;quot;));
        }

        if (name.equals(GET_CALL)) {
            uniqueResult = true;
        }
        else if (name.equals(SCROLL_CALL)) {
            scroll = true;
        }
        else if (name.equals(COUNT_CALL)) {
            count = true;
        }
        else if (name.equals(LIST_DISTINCT_CALL)) {
            resultTransformer = CriteriaSpecification.DISTINCT_ROOT_ENTITY;
        }

        createCriteriaInstance();

        // Check for pagination params
        if (name.equals(LIST_CALL) &amp;amp;&amp;amp; args.length == 2) {
            paginationEnabledList = true;
            orderEntries = new ArrayList&amp;lt;Order&amp;gt;();
            invokeClosureNode(args[1]);
        }
        else {
            invokeClosureNode(args[0]);
        }

        if (resultTransformer != null) {
            criteria.setResultTransformer(resultTransformer);
        }
        Object result;
        if (!uniqueResult) {
            if (scroll) {
                result = criteria.scroll();
            }
            else if (count) {
                criteria.setProjection(Projections.rowCount());
                result = criteria.uniqueResult();
            }
            else if (paginationEnabledList) {
                // Calculate how many results there are in total. This has been
                // moved to before the &amp;#39;list()&amp;#39; invocation to avoid any &amp;quot;ORDER
                // BY&amp;quot; clause added by &amp;#39;populateArgumentsForCriteria()&amp;#39;, otherwise
                // an exception is thrown for non-string sort fields (GRAILS-2690).
                criteria.setFirstResult(0);
                criteria.setMaxResults(Integer.MAX_VALUE);

                // Restore the previous projection, add settings for the pagination parameters,
                // and then execute the query.
                if (projectionList != null &amp;amp;&amp;amp; projectionList.getLength() &amp;gt; 0) {
                    criteria.setProjection(projectionList);
                } else {
                    criteria.setProjection(null);
                }
                for (Order orderEntry : orderEntries) {
                    criteria.addOrder(orderEntry);
                }
                if (resultTransformer == null) {
                    criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
                }
                else if (paginationEnabledList) {
                    // relevant to GRAILS-5692
                    criteria.setResultTransformer(resultTransformer);
                }
                // GRAILS-7324 look if we already have association to sort by
                Map argMap = (Map)args[0];
                final String sort = (String) argMap.get(GrailsHibernateUtil.ARGUMENT_SORT);
                if (sort != null) {
                    boolean ignoreCase = true;
                    Object caseArg = argMap.get(GrailsHibernateUtil.ARGUMENT_IGNORE_CASE);
                    if (caseArg instanceof Boolean) {
                        ignoreCase = (Boolean) caseArg;
                    }
                    final String orderParam = (String) argMap.get(GrailsHibernateUtil.ARGUMENT_ORDER);
                    final String order = GrailsHibernateUtil.ORDER_DESC.equalsIgnoreCase(orderParam) ?
                            GrailsHibernateUtil.ORDER_DESC : GrailsHibernateUtil.ORDER_ASC;
                    int lastPropertyPos = sort.lastIndexOf(&amp;#39;.&amp;#39;);
                    String associationForOrdering = lastPropertyPos &amp;gt;= 0 ? sort.substring(0, lastPropertyPos) : null;
                    if (associationForOrdering != null &amp;amp;&amp;amp; aliasMap.containsKey(associationForOrdering)) {
                        addOrder(criteria, aliasMap.get(associationForOrdering) + &amp;quot;.&amp;quot; + sort.substring(lastPropertyPos + 1),
                                order, ignoreCase);
                        // remove sort from arguments map to exclude from default processing.
                        @SuppressWarnings(&amp;quot;unchecked&amp;quot;) Map argMap2 = new HashMap(argMap);
                        argMap2.remove(GrailsHibernateUtil.ARGUMENT_SORT);
                        argMap = argMap2;
                    }
                }
                GrailsHibernateUtil.populateArgumentsForCriteria(grailsApplication, targetClass, criteria, argMap);
                GrailsHibernateTemplate ght = new GrailsHibernateTemplate(sessionFactory, grailsApplication);
                PagedResultList pagedRes = new PagedResultList(ght, criteria);
                result = pagedRes;
            }
            else {
                result = criteria.list();
            }
        }
        else {
            result = GrailsHibernateUtil.unwrapIfProxy(criteria.uniqueResult());
        }
        if (!participate) {
            hibernateSession.close();
        }
        return result;
    }

    if (criteria == null) createCriteriaInstance();

    MetaMethod metaMethod = getMetaClass().getMetaMethod(name, args);
    if (metaMethod != null) {
        return metaMethod.invoke(this, args);
    }

    metaMethod = criteriaMetaClass.getMetaMethod(name, args);
    if (metaMethod != null) {
        return metaMethod.invoke(criteria, args);
    }
    metaMethod = criteriaMetaClass.getMetaMethod(GrailsClassUtils.getSetterName(name), args);
    if (metaMethod != null) {
        return metaMethod.invoke(criteria, args);
    }

    if (isAssociationQueryMethod(args) || isAssociationQueryWithJoinSpecificationMethod(args)) {
        final boolean hasMoreThanOneArg = args.length &amp;gt; 1;
        Object callable = hasMoreThanOneArg ? args[1] : args[0];
        int joinType = hasMoreThanOneArg ? (Integer)args[0] : CriteriaSpecification.INNER_JOIN;

        if (name.equals(AND) || name.equals(OR) || name.equals(NOT)) {
            if (criteria == null) {
                throwRuntimeException(new IllegalArgumentException(&amp;quot;call to [&amp;quot; + name + &amp;quot;] not supported here&amp;quot;));
            }

            logicalExpressionStack.add(new LogicalExpression(name));
            invokeClosureNode(callable);

            LogicalExpression logicalExpression = logicalExpressionStack.remove(logicalExpressionStack.size()-1);
            addToCriteria(logicalExpression.toCriterion());

            return name;
        }

        if (name.equals(PROJECTIONS) &amp;amp;&amp;amp; args.length == 1 &amp;amp;&amp;amp; (args[0] instanceof Closure)) {
            if (criteria == null) {
                throwRuntimeException(new IllegalArgumentException(&amp;quot;call to [&amp;quot; + name + &amp;quot;] not supported here&amp;quot;));
            }

            projectionList = Projections.projectionList();
            invokeClosureNode(callable);

            if (projectionList != null &amp;amp;&amp;amp; projectionList.getLength() &amp;gt; 0) {
                criteria.setProjection(projectionList);
            }

            return name;
        }

        final PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(targetClass, name);
        if (pd != null &amp;amp;&amp;amp; pd.getReadMethod() != null) {
            ClassMetadata meta = sessionFactory.getClassMetadata(targetClass);
            Type type = meta.getPropertyType(name);
            if (type.isAssociationType()) {
                String otherSideEntityName =
                    ((AssociationType) type).getAssociatedEntityName((SessionFactoryImplementor) sessionFactory);
                Class oldTargetClass = targetClass;
                targetClass = sessionFactory.getClassMetadata(otherSideEntityName).getMappedClass(EntityMode.POJO);
                if (targetClass.equals(oldTargetClass) &amp;amp;&amp;amp; !hasMoreThanOneArg) {
                    joinType = CriteriaSpecification.LEFT_JOIN; // default to left join if joining on the same table
                }
                associationStack.add(name);
                final String associationPath = getAssociationPath();
                createAliasIfNeccessary(name, associationPath,joinType);
                // the criteria within an association node are grouped with an implicit AND
                logicalExpressionStack.add(new LogicalExpression(AND));
                invokeClosureNode(callable);
                aliasStack.remove(aliasStack.size() - 1);
                if (!aliasInstanceStack.isEmpty()) {
                    aliasInstanceStack.remove(aliasInstanceStack.size() - 1);
                }
                LogicalExpression logicalExpression = logicalExpressionStack.remove(logicalExpressionStack.size()-1);
                if (!logicalExpression.args.isEmpty()) {
                    addToCriteria(logicalExpression.toCriterion());
                }
                associationStack.remove(associationStack.size()-1);
                targetClass = oldTargetClass;

                return name;
            }
        }
    }
    else if (args.length == 1 &amp;amp;&amp;amp; args[0] != null) {
        if (criteria == null) {
            throwRuntimeException(new IllegalArgumentException(&amp;quot;call to [&amp;quot; + name + &amp;quot;] not supported here&amp;quot;));
        }

        Object value = args[0];
        Criterion c = null;
        if (name.equals(ID_EQUALS)) {
            return eq(&amp;quot;id&amp;quot;, value);
        }

        if (name.equals(IS_NULL) ||
                name.equals(IS_NOT_NULL) ||
                name.equals(IS_EMPTY) ||
                name.equals(IS_NOT_EMPTY)) {
            if (!(value instanceof String)) {
                throwRuntimeException(new IllegalArgumentException(&amp;quot;call to [&amp;quot; + name + &amp;quot;] with value [&amp;quot; +
                        value + &amp;quot;] requires a String value.&amp;quot;));
            }
            String propertyName = calculatePropertyName((String)value);
            if (name.equals(IS_NULL)) {
                c = Restrictions.isNull(propertyName);
            }
            else if (name.equals(IS_NOT_NULL)) {
                c = Restrictions.isNotNull(propertyName);
            }
            else if (name.equals(IS_EMPTY)) {
                c = Restrictions.isEmpty(propertyName);
            }
            else if (name.equals(IS_NOT_EMPTY)) {
                c = Restrictions.isNotEmpty(propertyName);
            }
        }

        if (c != null) {
            return addToCriteria(c);
        }
    }

    throw new MissingMethodException(name, getClass(), args);
}
// ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I do really hope never to have to understand such code... I&amp;#39;d be curious to find how
would such an automated test be written for this &lt;em&gt;invokeMethod&lt;/em&gt;, as I couldn&amp;#39;t find
the tests in this project.&lt;/p&gt;
&lt;h3&gt;What is wrong with this code?&lt;/h3&gt;
&lt;p&gt;Back to the original implementation, what would be wrong with such code?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It takes a lot of time for understand the code (the read cost);&lt;/li&gt;
&lt;li&gt;It is hard to test;&lt;/li&gt;
&lt;li&gt;Parsing the query is too much responsibility the SolrService class;&lt;/li&gt;
&lt;li&gt;If you just need some way of indexing and searching results in stored documents, you
shouldn&amp;#39;t be relying in a specific solution, like Solr. If you decide later to change
your Search solution from Solr to Elastic Search or using Lucene directly, you&amp;#39;ll need
to change a lot of code. It would be better to have a wrapper for something simple like this;&lt;/li&gt;
&lt;li&gt;It can become hard to change/maintain/debug;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Even if you try to split &lt;em&gt;processQuery&lt;/em&gt; into smaller methods, you would be required to pass
some common values over and over again, like &lt;em&gt;query&lt;/em&gt; and the &lt;em&gt;expressions&lt;/em&gt; array, that would
not only be an in-parameter but would be an out-parameter too as it would have to be changed
inside some methods... When that happens, it is a hint that the overall code needs a separate
class for doing the job. This is one of the simple rules I&amp;#39;ve learned in &lt;em&gt;Clean Code&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;The simple rules of Clean Code&lt;/h2&gt;
&lt;h3&gt;The top-bottom code writing approach&lt;/h3&gt;
&lt;p&gt;While reading the original example, the first thing you&amp;#39;ll see is the &lt;em&gt;processQuery&lt;/em&gt;
method declared in the SolrService class. What does it do? Why do we need it? Who is
using it? Only when we look forward, we&amp;#39;ll be able to detect that it is being used from
the &lt;em&gt;search&lt;/em&gt; method.&lt;/p&gt;
&lt;p&gt;I was always used to write code that way, writing the least dependent methods first and
the higher level ones as the latest ones. I guess I thought they should be declared first
before they could be mentioned. Maybe that was true for some procedural languages I&amp;#39;ve
started with before my first experience with OOP while reading a book about C++.&lt;/p&gt;
&lt;p&gt;But in all OO languages I know about, it is ok to declare your methods in any order. Writing
them top down makes it easier for another reader to understand your code because he/she will
read your high-level instructions first.&lt;/p&gt;
&lt;h3&gt;Avoid more than 5 lines in a single method&lt;/h3&gt;
&lt;p&gt;Keeping your methods really small will make it easier to understand them and to write unit
tests against them too. They&amp;#39;ll also be less error-prone.&lt;/p&gt;
&lt;h3&gt;Avoid methods with more than 2 or 3 parameters&lt;/h3&gt;
&lt;p&gt;Having lots of parameters in methods makes it really complicate to associate what is the meaning
of each parameter. Looking at this code, could you understand what is the meaning of the last
parameters?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;request.setAction(ACTION.POST, true, true, 10, false)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#39;d certainly have to checkout the API for &lt;a href=&quot;http://lucene.apache.org/solr/api/org/apache/solr/client/solrj/request/AbstractUpdateRequest.html&quot;&gt;AbstractUpdateRequest&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Avoid out-parameters&lt;/h3&gt;
&lt;p&gt;This is a typical example where you&amp;#39;d probably be better served by a separate class.&lt;/p&gt;
&lt;p&gt;When you find out some situation where you&amp;#39;d like to return multiple values
(I&amp;#39;m not talking about returning a single list, here) and you need some parameter
for returning them (and out-parameter), you should reconsider if you&amp;#39;re taking the
right path.&lt;/p&gt;
&lt;p&gt;Also, you should really try to avoid modifying any parameter as debugging such code
can be really frustrating.&lt;/p&gt;
&lt;h3&gt;Provide good names for your variables, classes and methods&lt;/h3&gt;
&lt;p&gt;This one is gold. Good names are essential for a good code reading experience. It
can save you several hours trying to understand some snippet of code.&lt;/p&gt;
&lt;p&gt;Take a look at the signature of the &lt;em&gt;invokeMethod&lt;/em&gt; method in the Grails-Hibernate
integration example code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Object invokeMethod(String name, Object obj)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wouldn&amp;#39;t it be easier to understand what it does if the signature was changed to
this one?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Object invokeMethodWith(String methodName, Object methodArguments)

// code would look like (just supposing, I&amp;#39;m not sure):
criteria.invokeMethodWith(&amp;quot;eq&amp;quot;, [attributeName, expectedValue])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What does &amp;quot;obj&amp;quot; mean in the actual implementation? It could be anything with such
generic description. Investing some time choosing good names for your methods and
variables can save a lot of time from others trying to understand what the code does.&lt;/p&gt;
&lt;h2&gt;The result of applying such simple rules&lt;/h2&gt;
&lt;p&gt;Just by making use of those simple rules, you&amp;#39;ll be able to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Easily read your code;&lt;/li&gt;
&lt;li&gt;Easily write your unit tests;&lt;/li&gt;
&lt;li&gt;Easily modify and evolve your logic;&lt;/li&gt;
&lt;li&gt;Have a well-documented code;&lt;/li&gt;
&lt;li&gt;Get rid of some otherwise hard-to-find bugs.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Some extra rules&lt;/h2&gt;
&lt;p&gt;Some rules I&amp;#39;ve being using for my entire life and I&amp;#39;m not sure if they are all documented
in the Clean Code book or not. But I&amp;#39;d like to talk a bit about them too.&lt;/p&gt;
&lt;h3&gt;Don&amp;#39;t use deep-depth blocks for handling validation rules&lt;/h3&gt;
&lt;p&gt;I&amp;#39;ve seen pseudo-code like this, so many times:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;declare square_root(number) {
  if (number &amp;gt;= 0) {
    do_real_calculations_with(number)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Often, there are even more validation rules inside each block and this style
gets really hard to read. And, worse than that, it is only protecting the software
from crashing or generating an unexpected exception, but it does not properly
handle bad inputs (negative numbers).&lt;/p&gt;
&lt;p&gt;Also, usually &lt;em&gt;do_real_calculations_with(number)&lt;/em&gt; is written as pages of code in
a way you won&amp;#39;t be able to see the enclosing brackets of the block in a single page.
Take a look again at the Hibernate-Grails integration code to see if you can easily
find out where the block beginning at &amp;quot;if (isCriteriaConstructionMethod(name, args)) {&amp;quot; ends.&lt;/p&gt;
&lt;p&gt;Even when you don&amp;#39;t have to do anything if the necessary conditions are not met,
I&amp;#39;d rather code this way:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;declare square_root(number) {
  if (number &amp;lt; 0) return // or raise &amp;quot;Taking the square root of negative numbers is not supported by this implementation&amp;quot;
  do_real_calculations_with(number)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a real example found in &lt;a href=&quot;https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/session/PersistentManagerBase.java&quot;&gt;PersistentManagerBase.java&lt;/a&gt;
from the Tomcat project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;protected void processMaxIdleSwaps() {

    if (!getState().isAvailable() || maxIdleSwap &amp;lt; 0)
        return;

    Session sessions[] = findSessions();
    long timeNow = System.currentTimeMillis();

    // Swap out all sessions idle longer than maxIdleSwap
    if (maxIdleSwap &amp;gt;= 0) {
        for (int i = 0; i &amp;lt; sessions.length; i++) {
            StandardSession session = (StandardSession) sessions[i];
            synchronized (session) {
                if (!session.isValid())
                    continue;
                int timeIdle = // Truncate, do not round up
                    (int) ((timeNow - session.getThisAccessedTime()) / 1000L);
                if (timeIdle &amp;gt; maxIdleSwap &amp;amp;&amp;amp; timeIdle &amp;gt; minIdleSwap) {
                    if (session.accessCount != null &amp;amp;&amp;amp;
                            session.accessCount.get() &amp;gt; 0) {
                        // Session is currently being accessed - skip it
                        continue;
                    }
                    if (log.isDebugEnabled())
                        log.debug(sm.getString
                            (&amp;quot;persistentManager.swapMaxIdle&amp;quot;,
                             session.getIdInternal(),
                             Integer.valueOf(timeIdle)));
                    try {
                        swapOut(session);
                    } catch (IOException e) {
                        // This is logged in writeSession()
                    }
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is hard to see what bracket is closing which bracket in the end... This could be rewritten as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;...
    if (maxIdleSwap &amp;lt; 0) return;
    for (int i = 0; i &amp;lt; sessions.length; i++) {
...
            if (timeIdle &amp;lt;= maxIdleSwap || timeIdle &amp;lt; minIdleSwap) continue;
            if (session.accessCount != null &amp;amp;&amp;amp; session.accessCount.get() &amp;gt; 0) continue;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Simple code should be handled first&lt;/h3&gt;
&lt;p&gt;The pattern is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;if some_condition
  lots of lines of complex code handling here
else
  simple handling for the case where some_condition is false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is a concrete example taken from &lt;a href=&quot;https://github.com/rails/rails/blob/master/activerecord/lib/active_record/explain.rb&quot;&gt;ActiveRecord::Explain&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;def logging_query_plan # :nodoc:
  threshold = auto_explain_threshold_in_seconds
  current   = Thread.current
  if threshold &amp;amp;&amp;amp; current[:available_queries_for_explain].nil?
    begin
      queries = current[:available_queries_for_explain] = []
      start = Time.now
      result = yield
      logger.warn(exec_explain(queries)) if Time.now - start &amp;gt; threshold
      result
    ensure
      current[:available_queries_for_explain] = nil
    end
  else
    yield
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I would rather write such code as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;def logging_query_plan # :nodoc:
  threshold = auto_explain_threshold_in_seconds
  current   = Thread.current
  return yield unless threshold &amp;amp;&amp;amp; current[:available_queries_for_explain].nil?
  queries = current[:available_queries_for_explain] = []
  start = Time.now
  result = yield
  logger.warn(exec_explain(queries)) if Time.now - start &amp;gt; threshold
  result
ensure
  current[:available_queries_for_explain] = nil
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this isn&amp;#39;t exactly the same as the original code in the case yield generates
some exception for the &amp;quot;else&amp;quot; code, but I&amp;#39;m sure this could be worked around.&lt;/p&gt;
&lt;h3&gt;Don&amp;#39;t handle separate exceptions when you don&amp;#39;t need to&lt;/h3&gt;
&lt;p&gt;I&amp;#39;ve often found this pattern while reading Java code and I believe that is the
result of using some Java IDE. The IDE will tell the developer that some exceptions
were not handled and will automatically fill the code as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;void myMethod() throws MyOwnException {
  try {
    someMethod()
  }
  catch(FileNotFoundException ex) {
    throw MyOwnException(&amp;quot;File was not found&amp;quot;)
  }
  catch(WrongPermissionException ex) {
    throw MyOwnException(&amp;quot;You don&amp;#39;t have the right permission to write to the file&amp;quot;)
  }
  catch(CorruptFileException ex) {
    throw MyOwnException(&amp;quot;The file is corrupted&amp;quot;)
  }
  ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#39;re only interested in gracefully handle exceptions to give your user a better
feedback, why doesn&amp;#39;t you just write this instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;void myMethod() throws MyOwnException {
  try {
    someMethod()
  } catch(Exception ex) {
    log.error(&amp;quot;Couldn&amp;#39;t perform XYZ action&amp;quot;, ex)
    throw new MyOwnException(&amp;quot;Sorry, couldn&amp;#39;t perform XYZ action. Please contact our support team and we&amp;#39;ll investigate this issue.&amp;quot;)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The original challenge actual implementation&lt;/h2&gt;
&lt;p&gt;And, finally, following those techniques, here is how I actually coded
that original challenge and implemented the tests in JUnit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;class SearchService {
  ...
  def search(query) {
    query = new QueryProcessor(query).processedQuery
    ...
    new SearchResult(solrServer.request(new SolrQuery(query)))
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;ll omit the implementation of SearchResult class, as it is irrelevant
to this specific challenge. I just want to point out that I&amp;#39;ve abstracted
the search feature in some wrapper classes for not exposing Solr internals.&lt;/p&gt;
&lt;p&gt;And here is the real implementation code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;package myappname.search

/* Solr behaves in an uncommon way:
 Even when configured for making an &amp;quot;AND&amp;quot; search, when a signal (+ or -)
 is prepended to any word, the ones that are not prepended are considered optionals.
 We don&amp;#39;t want that, so we&amp;#39;re prefixing all terms with a &amp;quot;+&amp;quot; unless they&amp;#39;re already
 prefixed.
*/
class QueryProcessor {
  private query, expressions = [], words = []

  QueryProcessor(query) { this.query = query }

  def getProcessedQuery() {
    removeHashesFromQuery()
    extractParenthesis()
    extractQuotedText()
    splitWords()
    addPlusSignToUnsignedWords()
    joinProcessedWords()
    replaceExpressions()
    query
  }

  private removeHashesFromQuery() { query = query.replaceAll(&amp;#39;#&amp;#39;, &amp;#39;&amp;#39;) }

  private extractParenthesis() {
    def matches = query =~ /\([^\(]*?\)/
    if (!matches) return
    replaceMatches(matches)
    // keep trying in case of nested parenthesis
    extractParenthesis()
  }

  private replaceMatches(matches) {
    matches.each {
      expressions &amp;lt;&amp;lt; it
      query = query.replace(it, &amp;quot;#{${expressions.size()}}&amp;quot;.toString())
    }
  }

  private extractQuotedText() {
    replaceMatches(query =~ /\&amp;quot;.*?\&amp;quot;/)
  }

  private splitWords() {
    words = query.split(&amp;#39; &amp;#39;).findAll{it}
  }

  private addPlusSignToUnsignedWords() {
    words = words.collect { word -&amp;gt;
      word[0] in [&amp;#39;-&amp;#39;, &amp;#39;+&amp;#39;] ? word : &amp;quot;+${word}&amp;quot;
    }
  }

  private joinProcessedWords() { query = words.join(&amp;#39; &amp;#39;) }

  private replaceExpressions() {
    def s = expressions.size()
    expressions.reverse().eachWithIndex { expression, i -&amp;gt;
      query = query.replace(&amp;quot;#{${s - i}}&amp;quot;, expression)
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the unit tests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;package myappname.search

import org.junit.*

class QueryProcessorTests {
  @Test
  void removeHashesFromQuery() {
    def p = new QueryProcessor(&amp;#39;some#hashes # in # query&amp;#39;)
    p.removeHashesFromQuery()
    assert p.query == &amp;#39;somehashes  in  query&amp;#39;
  }

  @Test
  void extractParenthesis() {
    def p = new QueryProcessor(&amp;#39;(abc (cde fgh)) no parenthesis transaction_id:(ijk) (lmn)&amp;#39;)
    p.extractParenthesis()
    assert p.query == &amp;#39;#{4} no parenthesis transaction_id:#{2} #{3}&amp;#39;
    assert p.expressions == [&amp;#39;(cde fgh)&amp;#39;, &amp;#39;(ijk)&amp;#39;, &amp;#39;(lmn)&amp;#39;, &amp;#39;(abc #{1})&amp;#39;]
  }

  @Test
  void extractQuotedText() {
    def p = new QueryProcessor(&amp;#39;some &amp;quot;quoted&amp;quot; text and &amp;quot;some more&amp;quot;&amp;#39;)
    p.extractQuotedText()
    assert p.query == &amp;#39;some #{1} text and #{2}&amp;#39;
    assert p.expressions == [&amp;#39;&amp;quot;quoted&amp;quot;&amp;#39;, &amp;#39;&amp;quot;some more&amp;quot;&amp;#39;]
  }

  @Test
  void splitWords() {
    def p = new QueryProcessor(&amp;#39;some #{1}   text and  id:#{2}  &amp;#39;)
    p.splitWords()
    assert p.words == [&amp;#39;some&amp;#39;, &amp;#39;#{1}&amp;#39;, &amp;#39;text&amp;#39;, &amp;#39;and&amp;#39;, &amp;#39;id:#{2}&amp;#39;]
  }

  @Test
  void addPlusSignToUnsignedWords() {
    def p = new QueryProcessor(&amp;#39;some #{1}   -text and  id:#{2}    +text  &amp;#39;)
    p.splitWords()
    p.addPlusSignToUnsignedWords()
    assert p.words == [&amp;#39;+some&amp;#39;, &amp;#39;+#{1}&amp;#39;, &amp;#39;-text&amp;#39;, &amp;#39;+and&amp;#39;, &amp;#39;+id:#{2}&amp;#39;, &amp;#39;+text&amp;#39;]
  }

  @Test
  void joinProcessedWords() {
    def p = new QueryProcessor(&amp;#39;&amp;#39;)
    p.words = [&amp;#39;+some&amp;#39;, &amp;#39;-minus&amp;#39;, &amp;#39;+#{1}&amp;#39;]
    p.joinProcessedWords()
    assert p.query == &amp;quot;+some -minus +#{1}&amp;quot;
  }

  @Test
  void replaceExpressions() {
    def p = new QueryProcessor(&amp;#39;+#{1} -minus +transaction_id:#{2}&amp;#39;)
    p.expressions = [&amp;#39;first&amp;#39;, &amp;#39;(23 or 98)&amp;#39;]
    p.replaceExpressions()
    assert p.query == &amp;#39;+first -minus +transaction_id:(23 or 98)&amp;#39;
  }

  @Test
  void processedQuery() {
    def p = new QueryProcessor(&amp;#39;coca-cola -pepsi  transaction_id:(34 or 76)&amp;#39;)
    assert p.processedQuery == &amp;#39;+coca-cola -pepsi +transaction_id:(34 or 76)&amp;#39;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That is it. I&amp;#39;d like you to share your opinions on other techniques I may have
not talked about here. Are there any improvements that you think would make
this code even easier to understand? I&amp;#39;d really appreciate any other considerations
you might have since I&amp;#39;m always very interested in writing Clean Code.&lt;/p&gt;
</content:encoded></item><item><title>Facebook, Twitter, Google+ - something is still missing</title><link>https://rosenfeld.page/articles/2011_12_30_facebook_twitter_google_something_is_still_missing/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2011_12_30_facebook_twitter_google_something_is_still_missing/</guid><pubDate>Fri, 30 Dec 2011 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What is missing in all those social networking media? Facebook, Orkut, Twitter, Google+?&lt;/p&gt;
&lt;h2&gt;Twitter&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ll start with specific issues for Twitter and then I&amp;#39;ll discuss the major general issue
none of them have managed to fix yet.&lt;/p&gt;
&lt;p&gt;Being able to fit an idea in just a few chars means it can&amp;#39;t be significant. Yet there are
lots of people trying to express their political opinions on Twitter as if had any meaningful
value.&lt;/p&gt;
&lt;p&gt;Twitter could be an useful platform if was basic a set of article titles followed by a link.
Something like Reddit, but instead of subscribing to topics (subreddit) one would subscribe to
some people&amp;#39;s suggested articles. I could certainly use Twitter if that was how it worked.&lt;/p&gt;
&lt;h2&gt;The big issue with all of them: lack of proper filtering by tag&lt;/h2&gt;
&lt;p&gt;It seems all social media didn&amp;#39;t realize yet that people are interested in multiple subjects,
but not in all of them.&lt;/p&gt;
&lt;p&gt;David Heinemeier Hansson (DHH) seems to be interested in Ruby, Rails, programming and car racing,
for example. David Chelimsky seems to be interested in Ruby and Choro (a Brazilian music genre).&lt;/p&gt;
&lt;p&gt;Maybe both Davids would be interested in listening to each other&amp;#39;s opinion on Ruby and
programming, but I&amp;#39;d suspect Chelimsky wouldn&amp;#39;t be interested in what DHH has to say about
car racing as much as DHH is probably not interested in videos from Chelimsky playing the cavaco
(a Brazilian instrument typically used in Choro and Samba).&lt;/p&gt;
&lt;p&gt;These days everyone has a strong opinion on many political topics, such as liberalism/communism,
feminism, left/right, immigration, abortion, religion or whatever trending subject. We&amp;#39;re all
specialists in everything and we get angry when our friends expresses themselves with an opposite
point of view. Sometimes that&amp;#39;s enough for completely breaking the relationship.&lt;/p&gt;
&lt;p&gt;This leads to a really toxic environment, since people are not interested in arguing at all.
They already have an strong opinion and they think they will be able to change other&amp;#39;s opinion
with their arguments but that never happens in practice. All they get is an hostile environment.&lt;/p&gt;
&lt;p&gt;Just like David Chelimsky, I do also love Choro and Samba and several of my friends are related
to those genres and we often meet each other to play Choro or Samba. That&amp;#39;s how we met in the
first place. Then I connected to them in Facebook and that&amp;#39;s when certain problems arise.&lt;/p&gt;
&lt;p&gt;Several of them are big supporters of Lula, Brazilian&amp;#39;s president between 2002 and 2010, while
I never supported him. I always found him to be a liar and corrupt and have always expressed
this way in Facebook. As a result I lost some of those friends that didn&amp;#39;t tolerate my opinions
on politics. On the other side we never had any kind of problems when playing together in a
Choro or Samba session.&lt;/p&gt;
&lt;p&gt;Social medias should be able to understand how toxic an environment could become if we don&amp;#39;t
filter what we&amp;#39;re going to say to other people. Or they seem to get it in the opposite way of
how I think things should work.&lt;/p&gt;
&lt;p&gt;Facebook and Google+ allows one to group their connections. So you&amp;#39;re able to group them by
topic like Ruby, Programming, Choro, Politics and so on. That could possibly fix the issue, but
there&amp;#39;s a problem. How can you possibly know who would be actually interested in what you have
to say regarding each topic. It could be a wild guess.&lt;/p&gt;
&lt;p&gt;It should work the other way around. Whenever publishing something we would tag the subject(s)
of the post from a list of tags we maintain. So, Chelimsky would be able to see that DHH
provides 2 tags: #racing and #programming. He might choose to subscribe to #programming. By
doing that he wouldn&amp;#39;t see in his timeline any posts by DHH related to racing or any other
general subject except for programming related ones. DHH on the other side would be able to
subscribe to the Ruby tag from Chelimsky and wouldn&amp;#39;t see videos of Choro sessions from
Chelimsky in his timeline. Since I&amp;#39;m both interested in Ruby and Choro I might not filter
Chelimsky&amp;#39;s posts at all.&lt;/p&gt;
&lt;p&gt;Sometimes the filter works the other way around. Rather than willing to filter in specific topics
we&amp;#39;d want to be able to filter out some tags. Maybe I&amp;#39;m interested in all activities from my
friends except for their opinion on politics. So it would be quite useful if we could &amp;quot;flag&amp;quot;
what we&amp;#39;d consider SPAM basically. I know some people who love to post comic/fun posts. I
don&amp;#39;t usually get the fun out of it, so if they tagged such posts as #joke I could opt to filter
out any post tagged that way.&lt;/p&gt;
&lt;p&gt;The lack of such tag subscription/filtering mechanism leads to a very toxic environment with lots
of unnecessary anger and a very polluted timeline. The result being a loss of interest in social
media as it wastes a lot of our time, while providing very little value. There are so many
jokes or political discussions that we often miss what our friends are actually doing.&lt;/p&gt;
&lt;p&gt;And the existing social media networks get it very close as they allow people to tag their posts.
But they don&amp;#39;t allow us to actually see filtered content only. Once they fix this missing bit I
think it will make all the difference.&lt;/p&gt;
</content:encoded></item><item><title>Testing JavaScript with Node.js, Jasmine and Sinon.js</title><link>https://rosenfeld.page/articles/programming/2011_10_05_testing_javascript_with_node_jasmine_and_sinon/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2011_10_05_testing_javascript_with_node_jasmine_and_sinon/</guid><pubDate>Wed, 05 Oct 2011 23:22:00 GMT</pubDate><content:encoded>&lt;p&gt;For some years now, I&amp;#39;ve been writing lots of JavaScript. Not that I chose to,
but it is the only available language for client-side programming. Well, not really
since there are some languages that will compile to JavaScript. So, I chose to work
with CoffeeScript lately, since it is far better than JavaScript for my tastes.&lt;/p&gt;
&lt;p&gt;All this client-side programming requires testing too. While sometimes testing using
real browsers suits better, tools like Selenium are extremely slow if you have tons of
JavaScript to test. So, I was looking for a faster alternative that allowed me to test
my client-side code.&lt;/p&gt;
&lt;p&gt;Before I present the approach I decided to take, I&amp;#39;d like to warn you that there are
lots of good alternatives out there. If you want to take a look at how to use the
excellent &lt;a href=&quot;http://www.phantomjs.org/&quot;&gt;PhantomJS&lt;/a&gt; headless webkit browser, you might be
interested in this &lt;a href=&quot;http://blog.ivandemarino.me/2011/07/09/Maven-PhantomJS-and-Jasmine-to-write-your-JS-Unit-Testing&quot;&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I decided to go with a solution based on Node.js, a fast runtime JavaScript environment
built on top of Google&amp;#39;s V8 engine. Even using Node.js, you&amp;#39;ll find out many good alternatives
like &lt;a href=&quot;http://zombie.labnotes.org/&quot;&gt;Zombie.js&lt;/a&gt;, which can also be integrated to the excellent
integration test framework &lt;a href=&quot;https://github.com/jnicklas/capybara&quot;&gt;Capybara&lt;/a&gt; through
&lt;a href=&quot;https://github.com/plataformatec/capybara-zombie&quot;&gt;capybara-zombie&lt;/a&gt;. It can also be integrated
to Jasmine through &lt;a href=&quot;https://github.com/mileskin/zombie-jasmine-spike&quot;&gt;zombie-jasmine-spike&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even though there are great options out there, I still chose another approach for no special reason.
The interesting thing about Node.js, is that there&amp;#39;s an interesting ecosystem behind it with tools
like NPM which is a package manager for Node, similar to apt on Debian, for instance. On Debian, it
can be installed with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;apt-get install -y node npm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But I would recommend installing just node through apt, and install npm using the instructions &lt;a href=&quot;http://npmjs.org/&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;curl http://npmjs.org/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reason for that is that the &lt;em&gt;search&lt;/em&gt; command of the &lt;em&gt;npm&lt;/em&gt; command provided by the Debian package
was not working for me, running the &lt;em&gt;list&lt;/em&gt; command instead. Maybe this happens only in the unstable
distribution, but I don&amp;#39;t want to get out of the main subject here.&lt;/p&gt;
&lt;p&gt;Since we want to test our client-side script, it is necessary to install some library to emulate the
browsers DOM, since Node won&amp;#39;t provide one itself. The &lt;a href=&quot;https://github.com/tmpvar/jsdom&quot;&gt;jsdom&lt;/a&gt; library
seems to be the de facto standard one for creating a DOM environment.&lt;/p&gt;
&lt;p&gt;I don&amp;#39;t really like to read assertions, prefering expectations instead. If you&amp;#39;re like me, you&amp;#39;ll like
the &lt;a href=&quot;http://pivotal.github.com/jasmine/&quot;&gt;Jasmine.js&lt;/a&gt; library for writing your expectations in JavaScript.
If you don&amp;#39;t want to write integration tests, chances are that you&amp;#39;ll need to mock your AJAX calls.
&lt;a href=&quot;http://sinonjs.org/&quot;&gt;Sinon.js&lt;/a&gt; is an excellent framework that will allow you to do that. And since I
avoid JavaScript itself at all cost, I&amp;#39;ll write all my examples using
&lt;a href=&quot;http://jashkenas.github.com/coffee-script/&quot;&gt;CoffeeScript&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your web framework, differently from &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt; doesn&amp;#39;t support CoffeeScript
by default, and still you got an interest on this language, you can use &lt;a href=&quot;https://github.com/TrevorBurnham/Jitter&quot;&gt;Jitter&lt;/a&gt;
to watch your CoffeeScript files and convert them to JavaScript on the fly. It will replicate your directory
structure, converting all your .coffee files to .js:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;jitter src/coffee/ web-app/js/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install all those dependencies with NPM:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;npm install jitter jasmine-node jsdom
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although you can install jQuery and Sinon.js with &amp;#39;&lt;em&gt;npm install jquery sinon&lt;/em&gt;&amp;#39;, that won&amp;#39;t make sense, since
you&amp;#39;ll want to load them from your DOM environment. So download Sinon.js to your hard-disk to get faster tests.&lt;/p&gt;
&lt;p&gt;I don&amp;#39;t practice TDD (or BDD) and I this is a conscious choice. I find it faster to write the implementation
first and then write the tests. So, proceeding with this approach, let me show you an example for a
&amp;quot;Terms and Conditions&amp;quot; page. Here&amp;#39;s a possible implementation (I&amp;#39;m showing only the client-side part):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/jquery.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;css/jquery.ui.css&amp;quot;&amp;gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/jquery-ui.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/wmd/showdown.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/show-terms-and-conditions.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/coreyti/showdown/&quot;&gt;Showdown&lt;/a&gt; is a JS library for converting
&lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt; to HTML. Here is the
show-terms-and-conditions.coffee equivalent in CoffeeScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;$ -&amp;gt;
  converter = new Attacklab.showdown.converter()
  lastTermsAndConditions = {}
  $.get &amp;#39;termsAndConditions/lastTermsAndConditions&amp;#39;, (data) -&amp;gt;
    lastTermsAndConditions = data
    $(&amp;#39;&amp;lt;div/&amp;gt;&amp;#39;).html(converter.makeHtml(lastTermsAndConditions.termsAndConditions))
      .dialog
        width: 800, height: 600, modal: true, buttons:
          &amp;#39;I agree&amp;#39;: onAgreement, &amp;#39;Log out&amp;#39;: onLogout

  onAgreement = -&amp;gt;
    $.post &amp;#39;termsAndConditions/agree&amp;#39;, id: lastTermsAndConditions.id, =&amp;gt;
      $(this).dialog(&amp;#39;close&amp;#39;)
      window.location = &amp;#39;../&amp;#39; # redirect to home

  onLogout = -&amp;gt;
    $(this).dialog(&amp;#39;close&amp;#39;)
    window.location = &amp;#39;../logout&amp;#39; # sign out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this will issue an AJAX request as soon as the page is loaded. So, we need to fake the AJAX
call before we run show-terms-and-conditions.js. This can be easily done with this fake-ajax.js, using Sinon.js:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;sinon.stub($, &amp;#39;ajax&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#39;re not using jQuery, you can try the &amp;quot;sinon.useFakeXMLHttpRequest()&amp;quot; documented in the &amp;quot;Fake XHR&amp;quot; example
in &lt;a href=&quot;http://sinonjs.org/&quot;&gt;Sinon.js site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ok, so here is a possible example of specification for this code in CoffeeScript.
&lt;a href=&quot;https://github.com/froots/jasmine-sinon&quot;&gt;Jasmine-sinon&lt;/a&gt; can help you to write better
expectations, so download it to &amp;#39;spec/js/jasmine-sinon.js&amp;#39;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-coffee&quot;&gt;# spec/js/show-terms-and-conditions.spec.coffee:

require &amp;#39;./jasmine-sinon&amp;#39; # wouldn&amp;#39;t you love if vanilla JavaScript also supported &amp;#39;require&amp;#39;?
dom = require &amp;#39;jsdom&amp;#39;

#f = (fn) -&amp;gt; __dirname + &amp;#39;/../../web-app/js/&amp;#39; + fn # if you prefer to be more explicit
f = (fn) -&amp;gt; &amp;#39;../../web-app/js/&amp;#39; + fn

window = $ = null

dom.env
  html: &amp;#39;&amp;lt;body&amp;gt;&amp;lt;/body&amp;gt;&amp;#39; # or require(&amp;#39;fs&amp;#39;).readFileSync(&amp;quot;#{__dirname}/spec/fixures/any.html&amp;quot;).toString()
  scripts: [&amp;#39;sinon.js&amp;#39;, f(&amp;#39;jquery/jquery.min.js&amp;#39;), f(&amp;#39;jquery/jquery-ui.min.js&amp;#39;), f(&amp;#39;wmd/showdown.js&amp;#39;), &amp;#39;ajax-faker.js&amp;#39;,
    f(&amp;#39;showTermsAndConditions.js&amp;#39;)]
  # src: [&amp;quot;console.log(&amp;#39;all scripts were loaded&amp;#39;)&amp;quot;, &amp;quot;var loaded=true&amp;quot;]
  done: (errors, _window) -&amp;gt;
    console.log(&amp;quot;errors:&amp;quot;, errors) if errors
    window = _window
    $ = window.$
    # jasmine.asyncSpecDone() if window.loaded

# We must tell Jasmine to wait until the DOM is loaded and the script is run
# Jasmine doesn&amp;#39;t support a beforeAll, like RSpec
beforeEach(-&amp;gt; waitsFor -&amp;gt; $) unless $
# another approach: (you should uncomment the line above for it to work)
# already_run = false
# beforeEach -&amp;gt; already_run ||= jasmine.asyncSpecWait() or true

describe &amp;#39;showing Terms and Conditions&amp;#39;, -&amp;gt;

  it &amp;#39;should get last Terms and Conditions&amp;#39;, -&amp;gt;
    @after -&amp;gt; $.ajax.restore() # undo the stubbed ajax call introduced by fake-ajax.js after this example.
    expect($.ajax).toHaveBeenCalledOnce()
    firstAjaxCallArgs = $.ajax.getCall(0).args[0]
    expect(firstAjaxCallArgs.url).toEqual &amp;#39;termsAndConditions/lastTermsAndConditions&amp;#39;
    firstAjaxCallArgs.success id: 1, termsAndConditions: &amp;#39;# title&amp;#39;

  describe &amp;#39;after set-up&amp;#39;, -&amp;gt;
    beforeEach -&amp;gt; window.sinon.stub $, &amp;#39;ajax&amp;#39;
    afterEach -&amp;gt; $.ajax.restore()
    afterEach -&amp;gt; $(&amp;#39;.ui-dialog&amp;#39;).dialog &amp;#39;open&amp;#39; # it is usually closed at the end of each example

    it &amp;#39;should convert markdown to HTML&amp;#39;, -&amp;gt; expect($(&amp;#39;h1&amp;#39;).text()).toEqual &amp;#39;title&amp;#39;

    it &amp;#39;should close the dialog, send a request to server and redirect to ../ when the terms are accepted&amp;#39;, -&amp;gt;
      $(&amp;#39;button:contains(I agree)&amp;#39;).click()
      ajaxRequestArgs = $.ajax.args[0][0]
      expect(ajaxRequestArgs.url).toEqual &amp;#39;termsAndConditions/agree&amp;#39;
      expect(ajaxRequestArgs.data).toEqual id: 1

      ajaxRequestArgs.success()
      expect(window.location).toEqual &amp;#39;../&amp;#39;
      expect($(&amp;#39;.ui-dialog:visible&amp;#39;).length).toEqual 0

    it &amp;#39;should close the dialog and redirect to ../logout when the terms are not accepted&amp;#39;, -&amp;gt;
      # the page wasn&amp;#39;t really redirected in this simulation by the prior example
      $(&amp;#39;button:contains(Log out)&amp;#39;).click()
      expect(window.location).toEqual &amp;#39;../logout&amp;#39;
      expect($(&amp;#39;.ui-dialog:visible&amp;#39;).length).toEqual 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can run this spec with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;jasmine-node --coffee spec/js/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output should be something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Started
....

Finished in 0.174 seconds
2 tests, 9 assertions, 0 failures
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of writing &amp;quot;expect($(&amp;#39;.ui-dialog:visible&amp;#39;).length).toEqual 0&amp;quot;, BDD would advice you to write
&amp;quot;expect($(&amp;#39;.ui-dialog&amp;#39;)).toBeVisible()&amp;quot; instead. Jasmine allows you to write custom matchers. Take a look
at &lt;a href=&quot;https://github.com/rosenfeld/jasmine-node-jquery-matchers&quot;&gt;my jQuery matchers&lt;/a&gt; for an example.&lt;/p&gt;
&lt;p&gt;Unfortunately, due to &lt;a href=&quot;https://github.com/tmpvar/jsdom/issues/353&quot;&gt;a bug&lt;/a&gt; in jsdom, the expected
implementations of toBeVisible and toBeHidden won&amp;#39;t work for my cases, where I usually do that by
toggling the &lt;em&gt;hidden&lt;/em&gt; CSS class (&lt;em&gt;.hidden {display: none}&lt;/em&gt;) of my elements. So, I check for this
CSS class on my jQuery matchers.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#39;m just starting to write tests this way. Maybe there are better ways of writing tests like those.&lt;/p&gt;
&lt;p&gt;Finally, if you want, you can also set up some auto-testing environment using a tool such as &lt;a href=&quot;https://github.com/guard/guard&quot;&gt;Guard&lt;/a&gt;
that will watch your JavaScript (or CoffeeScript) files for changes and call jasmine-node on them. Here is an example Guardfile:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;guard &amp;#39;jasmine-node&amp;#39;, jasmine_node_bin: File.expand_path(&amp;quot;#{ENV[&amp;#39;HOME&amp;#39;]}/node_modules/jasmine-node/bin/jasmine-node&amp;quot;) do
  watch(%r{^(spec/js/[^\.].+\.spec\.coffee)}) { |m| m[1] }
  watch(&amp;#39;spec/js/jasmine-sinon.js&amp;#39;){ &amp;#39;spec/js/&amp;#39; }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have any tips, please leave a comment.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
</content:encoded></item><item><title>Adding parts of a modified file to git stage</title><link>https://rosenfeld.page/articles/programming/2011_08_13_adding_parts_of_a_modified_file_to_git_stage/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2011_08_13_adding_parts_of_a_modified_file_to_git_stage/</guid><pubDate>Sat, 13 Aug 2011 15:35:00 GMT</pubDate><content:encoded>&lt;p&gt;Have you always wanted to add just part of your modified file to the index stage?&lt;/p&gt;
&lt;p&gt;Usually, that happens when you&amp;#39;re working in a feature or bug and then realizes another issue in the file.
It could be another bug, interesting feature, documentation, comment or just code formatting.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re like me, you won&amp;#39;t include both modifications into a single commit. Then what to do?&lt;/p&gt;
&lt;p&gt;What I used to do when I realized this before actually fixing that bug was calling &amp;quot;git stash&amp;quot;, fix the bug
and &amp;quot;git stash pop&amp;quot;. This works well for simple fixes, if you didn&amp;#39;t change your database, so that the
application will continue to work after &amp;quot;git stash&amp;quot;.&lt;/p&gt;
&lt;p&gt;But what if you have already fixed the code? You could undo the fix, save the file, add it to index, and then
redo the fix. Believe me, I&amp;#39;ve done that several times.&lt;/p&gt;
&lt;p&gt;But I won&amp;#39;t do it anymore! Don&amp;#39;t worry, I&amp;#39;ll keep my commits separate. It&amp;#39;s just that I found a better way
of doing this: &amp;quot;&lt;strong&gt;git add -e&lt;/strong&gt;&amp;quot; (or &amp;quot;&lt;strong&gt;git add -p&lt;/strong&gt;&amp;quot; and choosing the &amp;quot;&lt;strong&gt;e&lt;/strong&gt;&amp;quot; option). Go try it if you
don&amp;#39;t know this already. Much easier to try it than to try to explain it! ;) Also &amp;quot;git help add&amp;quot; will
explain it better than me. See &lt;em&gt;EDITING PATCHES&lt;/em&gt; section.&lt;/p&gt;
</content:encoded></item><item><title>Why I Prefer Rails over Grails</title><link>https://rosenfeld.page/articles/programming/2011_08_07_why_i_prefer_rails_over_grails/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2011_08_07_why_i_prefer_rails_over_grails/</guid><pubDate>Sun, 07 Aug 2011 21:20:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#39;ve been willing to write such an article for 2 years now. A recent thread in Grails users mailing list
triggered the initiative to finally write it. Actually, I was replying a message but it became too big
and I decided to take the chance to write an article on the subject.&lt;/p&gt;
&lt;h2&gt;Should I use Grails?&lt;/h2&gt;
&lt;p&gt;That was the thread subject. And the text following is my answer.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been working with Grails for more than 2 years now. Before that, I learned Rails in 2007 and like it.
I didn&amp;#39;t move to Grails because I love Grails though.&lt;/p&gt;
&lt;p&gt;I moved because I changed my job and Grails was used in the new job. I&amp;#39;ve changed my job again last month,
initially to work with Rails but then, when they found out that I also knew Groovy and Grails, they decided
to offer me another Grails opportunity.&lt;/p&gt;
&lt;p&gt;So here I am, working with Grails for probably more two years at least I would guess... Since 2007, I never
stopped watching Rails or Ruby closely, so I think I&amp;#39;m pretty able to compare both.&lt;/p&gt;
&lt;p&gt;Then, I would say that choosing between them will depend on what you want to achieve. If you want to run your
application in a Java web container, maybe Grails is the way to go. I&amp;#39;ve never deployed a Rails application
with JRuby and Warbler, so I&amp;#39;m just guessing.&lt;/p&gt;
&lt;p&gt;If you just want to be able to integrate your web application to your legacy Java code, than both Groovy and JRuby
will allow you to do that easily. Differently from Groovy, though, JRuby will allow you to &amp;quot;require&amp;quot; jar&amp;#39;s at run-time
easily. But maybe Grails has better integration with Maven. Again, I say maybe because I never tried to do that with
the JRuby + Warbler approach besides really simple experiments.&lt;/p&gt;
&lt;p&gt;If you just want to write web applications, than you&amp;#39;re in the situation as me and I can help you more on that.&lt;/p&gt;
&lt;p&gt;Let me explain to you what are the reasons I prefer Rails myself and what I don&amp;#39;t like in Grails. I invite all Grails
community to participate in this discussion and help alleviate the shortcomings perceived by me about Grails.&lt;/p&gt;
&lt;h2&gt;Testing&lt;/h2&gt;
&lt;p&gt;I don&amp;#39;t know if that is your case, but I don&amp;#39;t even consider writing a new application without a good test coverage.
Unfortunately I was not given the opportunity to do that yet because the companies I worked with didn&amp;#39;t want to give
me time for writing the tests.&lt;/p&gt;
&lt;p&gt;Unfortunately, this seems to be a common approach in Grails community as most of the plugins I used didn&amp;#39;t have test
coverage, so I guess my companies were not alone. In the other side, it is a strong practice of Rubysts to write tests
for their code, including most plugins available. Also, the Rails code base itself has a great test coverage. In the
other side I&amp;#39;ve experienced some bugs in Grails like runtime dependencies added to BuildConfig.groovy not being included
in the war in previous releases which suggests me that its test coverage is not comparable with the Rails&amp;#39; one.&lt;/p&gt;
&lt;p&gt;Then, if you search for books written entirely about tests for Rails, you&amp;#39;ll find lots of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://pragprog.com/book/achbd/the-rspec-book&quot;&gt;The Rspec Book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pragprog.com/book/nrtest/rails-test-prescriptions&quot;&gt;Rails Test Prescriptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pragprog.com/book/hwcuc/the-cucumber-book&quot;&gt;The Cucumber Book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, testing uses to be one of the first chapters in almost Rails book, reflecting the importance
that Ruby and Rails users give to automated testing.&lt;/p&gt;
&lt;p&gt;Also, there are tons of projects dedicated to some part of test creation for Ruby:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.bootspring.com/2010/09/22/minitest-rubys-test-framework/&quot;&gt;MiniTest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rspec.info/&quot;&gt;Rspec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://cukes.info/&quot;&gt;Cucumber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jnicklas/capybara&quot;&gt;Capybara&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brynary/webrat/wiki&quot;&gt;Webrat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://faker.rubyforge.org/&quot;&gt;Faker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/grosser/parallel_tests&quot;&gt;Parallel Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bmabey/database_cleaner&quot;&gt;Database Cleaner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;And several others.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the other side, I didn&amp;#39;t find a single book specialized in testing Grails applications. I&amp;#39;ve only seen a single
small chapter about testing in Grails in some Grails books. Also, there are lots of great articles and tutorials
on Rails testing while I can&amp;#39;t find good resources on Grails testing.&lt;/p&gt;
&lt;p&gt;Since I prefer specifications over assertions, I started to write some tests for Grails with &lt;a href=&quot;http://www.easyb.org/&quot;&gt;EasyB&lt;/a&gt;.
But its documentation and features can&amp;#39;t be compared with the Rspec one. Also, I don&amp;#39;t find so many alternatives in the
Groovy world yet. I have some problems with EasyB, but it was the best I could find and that&amp;#39;s what I&amp;#39;ve being using for
testing Groovy and Grails code.&lt;/p&gt;
&lt;p&gt;Also, while I can write unit tests for Rails that can actually touch the database, this is not possible with Grails. Grails
will force me to use mocks in unit tests. But if part of the logic involves direct queries to the database, which is almost
always my situation, then I&amp;#39;m forced to use integration tests for all my tests which, added to the slow boot time for Grails
applications, make test writing a very slow task. Also, writing an integration test when actually I want to unit test my class
just because of a Grails limitation doesn&amp;#39;t seem right for me.&lt;/p&gt;
&lt;h2&gt;Documentation&lt;/h2&gt;
&lt;p&gt;Grails documentation is usually sparse with references to Hibernate&amp;#39;s documentation, Spring&amp;#39;s documentation, Shiro&amp;#39;s documentation etc.
While I agree that using existent libraries is a good thing, I also like to see a well organized and comprehensive documentation instead
of jumping between several sites, each one using a different documentation organization and style. Specially when most of them are
crappy for my taste.&lt;/p&gt;
&lt;p&gt;In the other side, I usually find &lt;a href=&quot;http://guides.rubyonrails.org/&quot;&gt;great documentation&lt;/a&gt; for Rails and its several available
plugins with concise information showing how to use them in a glance.&lt;/p&gt;
&lt;h2&gt;Speed of development&lt;/h2&gt;
&lt;h3&gt;Class automatic reloading&lt;/h3&gt;
&lt;p&gt;This seems to be changing in Grails 2.0, but for the last 2 years I&amp;#39;ve had enormous trouble writing Grails application because every change
I make in my domain classes (which I do often), Grails will restart my application, loosing any session and spending a lot of time in the
rebooting process. This really slows down the development time. This also happens to classes under &lt;em&gt;src/&lt;/em&gt; while doesn&amp;#39;t happen to controllers and GSP&amp;#39;s.&lt;/p&gt;
&lt;h3&gt;Necessary time for booting&lt;/h3&gt;
&lt;p&gt;Compare the time of booting a fresh Grails application with booting a Rails one. Rails will make the application available barely instantly.
This becomes more annoying when Grails will insist in rebooting after changing some classes and while the application gets bigger or when you
do lots of processing in Bootstrap. In Rails, this is super fast in development mode because of the Ruby &lt;em&gt;autoload&lt;/em&gt; feature that will allow
you to lazily evaluate your classes.&lt;/p&gt;
&lt;h2&gt;Language API and features&lt;/h2&gt;
&lt;p&gt;Groovy API is based in Java API, which was badly designed in my opinion. Ruby, differently from Java, will have Date, DateTime and Time classes,
for instance. Java, in the other side, has java.util.Date and java.sql.TimeStamp, etc. I&amp;#39;ve seen people arguing that it&amp;#39;s because Ruby is much
newer, but actually both languages were born in 1995.&lt;/p&gt;
&lt;p&gt;The Ruby API is also very well written in my opinion and has also great documentation. Everything fits great in Ruby while Groovy tries to make
some methods simpler adding methods to standard Java classes but still it is built on top of Java&amp;#39;s API, which means it couldn&amp;#39;t be as well
integrated and well-thought as one that was built specifically considering the language features from the beginning.&lt;/p&gt;
&lt;p&gt;With regards to the language itself, I really prefer the Ruby way of monkey-patching (reopening classes) and its way of writing meta-programming.
Specially, I love Ruby modules and the concept of mixins (instead of supporting multiple inheritance), while I don&amp;#39;t think there&amp;#39;s something like
that in Groovy.&lt;/p&gt;
&lt;p&gt;Also, I don&amp;#39;t understand why Groovy created a new syntax (&amp;quot;&amp;quot;&amp;quot; - triple quotes) for multi-line strings instead of allowing multi-line
strings using single quotes just like Ruby. On the other hand, I don&amp;#39;t like the fact that Ruby doesn&amp;#39;t support multi-line comment
like most languages (no, don&amp;#39;t tell me that =begin and =end were really intended to be used as multi-line comments).&lt;/p&gt;
&lt;h2&gt;Dependency management&lt;/h2&gt;
&lt;p&gt;Ruby had &lt;a href=&quot;https://rubygems.org/&quot;&gt;RubyGems&lt;/a&gt; for a long time for managing dependencies and easily install gems (libraries, programs).
There&amp;#39;s a huge repository of Ruby gems. Java has &lt;a href=&quot;http://maven.apache.org/&quot;&gt;Maven&lt;/a&gt;, but Maven doesn&amp;#39;t allow you to specify
&amp;quot;hibernate &amp;gt; 3.6&amp;quot;. You need to be specific.&lt;/p&gt;
&lt;p&gt;And then, Maven will try to solve conflicts if you need a dependency that depends in Hibernate 3.6.5 and another one that depends on Hibernate 3.6.6.
And Maven will not always be able to solve this dependency well.&lt;/p&gt;
&lt;p&gt;In Ruby, suppose one gem depends on &amp;quot;hibernate &amp;gt;= 3.6&amp;quot; and another one depends on &amp;quot;hibernate = 3.6.6&amp;quot;. Then RubyGems will be able to choose hibernate 3.6.6.
But what if your application depends on latest gem version? Than you don&amp;#39;t specify the version and it will fetch the last one. Then, say that some
time has passed and another developer needs to replicate the dependencies. It wouldn&amp;#39;t be so uncommon that the newest version of one of the
dependencies is not compatible anymore with that one used when the application was first developed. For solving this specific problem Rails
had a rake task (rake rails:freeze) in its early times that would copy the gems to a vendor folder so that the application could be easily deployed
anywhere. But that wasn&amp;#39;t a really good solution and then, some years ago, &lt;a href=&quot;http://yehudakatz.com/&quot;&gt;Yehuda Katz&lt;/a&gt; released
&lt;a href=&quot;http://gembundler.com/&quot;&gt;Bundler&lt;/a&gt;, which solved this problem by writing a file that recorded all gem versions used in last &amp;quot;bundle&amp;quot; command which
allowed that configuration to be replicated anytime without vendoring all gems.&lt;/p&gt;
&lt;p&gt;Bundler is a great tool and all Rails application starting from Rails 3.0 use it for managing dependencies. I don&amp;#39;t know a similar handy project for Groovy.&lt;/p&gt;
&lt;h2&gt;Mountable applications&lt;/h2&gt;
&lt;p&gt;The next version of Rails (3.1.0), soon to be released, will allow mounting some applications in certain paths that could interact with the main app.
I guess Django supported this for a longer time, but Grails won&amp;#39;t support this feature in 2.0 as far as I know. This is also a great feature.&lt;/p&gt;
&lt;h2&gt;Memory usage&lt;/h2&gt;
&lt;p&gt;Unless JRuby is being used, you don&amp;#39;t need to previously allocate memory to your application. The memory will increase as it needs more memory.
That means you can run lots of Rails application in the same time in your development environment without being concerned about limiting their
memory before running the application. That usually means you have more free available RAM.&lt;/p&gt;
&lt;h2&gt;Database evolution&lt;/h2&gt;
&lt;p&gt;My first web applications were written in Perl about 15 years ago or more. While at Electrical Engineering college I didn&amp;#39;t have lots of web
development spending most of my developing time with C and C++, working in embedded and real-time systems.&lt;/p&gt;
&lt;p&gt;In 2007, I was back to web development and needed to update my knowledge. When I looked for web frameworks, I was evaluating mostly TurboGears,
Django and Rails, after discarding MS .NET and Java-based ones. I didn&amp;#39;t know Ruby nor Python at that time so I wasn&amp;#39;t biased against any of them.
The argument that I really bought while choosing Rails over the other alternatives was the database evolution approach. If I remember correctly,
both TurboGears and Django used the same approach used by Grails. You write your domain classes and then generate the database tables based on these
classes attributes. I didn&amp;#39;t like this approach at all because I was really concerned about database evolution. In the other hand, Rails supported
database migrations and the model classes attributes didn&amp;#39;t have to be replicated since they would be dynamically fetched from the mapped database
table at run-time during Rails initializatin. I really prefer this approach but database migrations only seems to be supported by the Grails framework
itself in Grails 2.0, which wasn&amp;#39;t released yet by the time I&amp;#39;m writing this.&lt;/p&gt;
&lt;p&gt;For a long time we used to &amp;quot;dbCreate=update&amp;quot; in DataSource.groovy and that is simple not maintainable. I hope Grails 2.0 will teach developers best
practices like those used by Rails since always.&lt;/p&gt;
&lt;h2&gt;Framework API&lt;/h2&gt;
&lt;p&gt;Regarding the framework API itself, I really prefer the Rails API. There are lots of useful DSLs, that I don&amp;#39;t find in Grails, specially for defining
hooks like before_save, after_save, before_validation, etc. You can specify these hooks in many useful ways and calling them multiple times. Also,
instead of static variables you have a declarative DSL for defining associations like has_many, belongs_to, etc. I also always found odd that Grails
used closures instead of methods for controller&amp;#39;s actions, although this seems to have changed to better in next to be released Grails. Also, I like
the fact that Rails generators will create controllers inherited from ApplicationController by default, which means you can add methods to the 
ApplicationController class if you want to add them to all controllers.&lt;/p&gt;
&lt;p&gt;Also, Rails allow me to specify which layout to apply directly in the controller instead of in ERB (GSP equivalent). Also, I don&amp;#39;t need to write
boilerplate code in my views like in GSPs.&lt;/p&gt;
&lt;h2&gt;Vim support&lt;/h2&gt;
&lt;p&gt;I&amp;#39;m a Vim user and Vim support for Groovy indentation and code highlighting is terrible. In the other side, there&amp;#39;s good support for the Ruby
language and the Rails framework.&lt;/p&gt;
&lt;h2&gt;Concerns about good default&lt;/h2&gt;
&lt;p&gt;Rails has always been worried for offering good default for web applications. This is specially true with security concerns. All text will be
sanitized inside &amp;quot;&amp;lt;%= ... %&amp;gt;&amp;quot; blocks unless explicitly said not to do that. In Grails you can do that, but that is not set by default and will
only work with the &amp;quot;${...}&amp;quot; style, which can&amp;#39;t be always used as my long experience with Grails has showed. I&amp;#39;m not sure when they&amp;#39;re not allowed
through because it never made sense to me... :( But it seems the problem is using this syntax in a nested context like
&amp;quot;${[something, &amp;quot;abc: ${2 * someValue}&amp;quot;].join(&amp;#39;&amp;lt;br/&amp;gt;&amp;#39;)}&amp;quot; but I don&amp;#39;t remember exactly.&lt;/p&gt;
&lt;h2&gt;Interactive console and tab-completion&lt;/h2&gt;
&lt;p&gt;Another time-saving while writing Rails applications is that auto-complete works in the interactive console (irb) and the &amp;quot;delete&amp;quot; key works
as expected in Linux, differently from &amp;quot;groovysh&amp;quot;. I&amp;#39;ve also opened an issue in JIRA presenting a patch to Jline to fix this annoyance that was
also present with JRuby at that time. JRuby fixed the problem but groovysh still doesn&amp;#39;t behaves correctly with regards to the &amp;quot;delete&amp;quot; key.&lt;/p&gt;
&lt;p&gt;The tab-completion will be also available while debugging a Ruby application using the ruby-debugger gem for instance. And I can even debug
Ruby applications in Vim, &lt;a href=&quot;/en/articles/2010-12-26-achieving-productivity-with-vim-as-ide&quot;&gt;my favorite editor&lt;/a&gt;. :)&lt;/p&gt;
&lt;h2&gt;Hard to debug errors&lt;/h2&gt;
&lt;p&gt;Errors in GSP&amp;#39;s will display unrelated lines.  Also, the stack-trace is so big when errors happen, as usual in Java applications, that a
friend called them MonsterExceptions.&lt;/p&gt;
&lt;p&gt;Both of them were said to be fixed for Grails 2.0 but I didn&amp;#39;t test it yet.&lt;/p&gt;
&lt;p&gt;Rails errors on the other hand are very precise and easy to find the source of the error.&lt;/p&gt;
&lt;h2&gt;New code - old behavior&lt;/h2&gt;
&lt;p&gt;I remember that one of the oddest behavior I experienced while first learning Grails was that after fixing some piece of code that bug
persisted and some while later it worked. It was the first time in my life as a programmer that I&amp;#39;ve seen such behavior. In Rails, when you
change some code, the change will be in effect immediately or it won&amp;#39;t make effect at all until you restart your application depending on
what you&amp;#39;re modifying. But since Java didn&amp;#39;t support listening to file-system events asynchronously until the recent Java 7, Java applications
use to implement file-change monitoring using the poller method. So, it may take a while before your changes make effect and you&amp;#39;ll never know
if the file was already recompiled or not.&lt;/p&gt;
&lt;h2&gt;Final words&lt;/h2&gt;
&lt;p&gt;Actually, I was expecting to write a more detailed article some years ago with more concrete examples but that would take some time and
that&amp;#39;s the reason why I didn&amp;#39;t write it before. But, as I was replying the message by e-mail, the answer was becoming so big that I decided
to write such an article even if it&amp;#39;s not the way I would like it to be. I hope I get some time in the future to polish it. Also, as I get
some feedback from Groovy and Grails users and after Grails 2.0 is finally released, I intend to update this article to reflect the changes
and any possible mistake that I could have made, as soon as I get some time.&lt;/p&gt;
&lt;p&gt;So, sorry for the unpolished article, but that&amp;#39;s what I can currently write. I hope it can be useful anyway. So, good luck in your framework
decision, whatever it be!&lt;/p&gt;
</content:encoded></item><item><title>How to write maintainable code?</title><link>https://rosenfeld.page/articles/programming/2011_08_06_how_to_write_maintainable_code/</link><guid isPermaLink="true">https://rosenfeld.page/articles/programming/2011_08_06_how_to_write_maintainable_code/</guid><pubDate>Sat, 06 Aug 2011 08:37:00 GMT</pubDate><content:encoded>&lt;p&gt;I have been willing to write such an article for a long time and finally found some inspiration and time for doing it.&lt;/p&gt;
&lt;h2&gt;Working software does not suffice&lt;/h2&gt;
&lt;p&gt;No software is finished. Even Vi, which was created in 1976, is not finished. If no one is working in some software anymore
it just means it is not being maintained or has been replaced by another one. That means your code will be changed or
entirely replaced.&lt;/p&gt;
&lt;p&gt;Unless you&amp;#39;re expecting your software to be replaced soon, you should consider writing maintainable code. It&amp;#39;s very important
to your code to be readable and maintainable because most of the time developers will spend reading it. So, while knowing
well your editor is important, you should consider spending more time refactoring your code to make it more readable than
finding new ways of writing efficiently using your editor because a clean source code will save you much more time than any
editor key mapping. But also, a good editor/IDE will also help you to refactor your code.&lt;/p&gt;
&lt;h2&gt;Continuous refactoring&lt;/h2&gt;
&lt;p&gt;You should really apply the good advices present in all books about Agile Software Developing since it is the only way
I know of writing software that actually works in the real world. I&amp;#39;ll not talk about Agile in this article, since it is
out of the scope and there are also great books out there about this subject. I&amp;#39;m assuming that the reader is familiar
with the subject though for better understanding this article. Here are the software writing guidelines that I&amp;#39;m talking
about, although I won&amp;#39;t explain the reasoning behind them, as they are a bit long and all books and articles on the
subject will explain them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don&amp;#39;t write code for the future&lt;/li&gt;
&lt;li&gt;Write automated tests that cover your requirements&lt;/li&gt;
&lt;li&gt;Continuous refactoring (will be extended in this topic)&lt;/li&gt;
&lt;li&gt;Continuous integration&lt;/li&gt;
&lt;li&gt;Continuous delivering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since you&amp;#39;ll be writing code for today&amp;#39;s usage, sometime you&amp;#39;ll face the situation where you need to write a new feature
that shares lots of implementation details of a prior feature. You shouldn&amp;#39;t be copying and pasting code from the prior
feature. This seems obvious but if I didn&amp;#39;t often find code written that way I wouldn&amp;#39;t be talking about this. WARNING:
whenever you find yourself copying and pasting some code, even for different projects, you should think twice. Most
probably you should separate the common part in another method, class or library. Some languages will require some
boilerplate code, but make sure you&amp;#39;re copying and pasting only the necessary boilerplate if that&amp;#39;s your case.&lt;/p&gt;
&lt;p&gt;The commonest reason why developers don&amp;#39;t rafactor their code is because they&amp;#39;re afraid of breaking some critical
production system. This is often related to the lack of a good suite of automated tests. Specially if your application
is a critical production system, it should be covered by tests. The more you copy and paste code, the harder it will
be to evolve the code base and understand it.&lt;/p&gt;
&lt;p&gt;The same bug will also happen in multiple places in the source code and
even if you fix it in some part of the code, the bug will show up again on Friday, 5pm, and you&amp;#39;ll have to cancel your
weekend planned schedule to work hard to find a hidden bug that was already fixed in other part of the code but you
don&amp;#39;t know that because you were not the one that fixed it. And people will be asking you why does it take so long
for fixing the application under production in the most critical time where it shouldn&amp;#39;t really fail while presenting
it to a big potential client corporation!&lt;/p&gt;
&lt;h2&gt;Automated test writing&lt;/h2&gt;
&lt;p&gt;TODO: talk about test simplicity, coverage, documentation tool and careless about TDD or testing after.
TODO: talk about test priorizing.
TODO: talk about mocks and importance of speed and isolation of concerns&lt;/p&gt;
&lt;h2&gt;Keep your code minimal&lt;/h2&gt;
&lt;p&gt;You should really keep your code minimal to be polite with the other developers that will work in your code some time
later. Maybe that developer will be you again. Having small methods, classes and files will help reading the code
without the need of scrolling the text. Also, some editors like Vim allow you to display multiple source files at the
same time. Having small methods will help you to understand the overall code.&lt;/p&gt;
&lt;h2&gt;Naming&lt;/h2&gt;
&lt;p&gt;TODO: talk about spending time thinking in good names&lt;/p&gt;
&lt;h2&gt;Avoid comments&lt;/h2&gt;
&lt;p&gt;TODO: talk about how comments can be avoided with clean code&lt;/p&gt;
&lt;h2&gt;Choose a good language if possible&lt;/h2&gt;
&lt;p&gt;TODO: Compare C++ and Java to dynamic languages like Ruby, Python or Groovy
TODO: talk about tradeoffs and performance concerns vs development speed
TODO: talk about legacy Java code and JRuby, Groovy, Scala, Clojure and JPython.
TODO: also talk about network-based API integration&lt;/p&gt;
&lt;h2&gt;Adopt great frameworks and libraries&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Upgrade often&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Keep It Super Simple - the KISS principle&lt;/h2&gt;
&lt;p&gt;TODO: Avoid uncommon solutions and complicated architectures&lt;/p&gt;
&lt;h2&gt;Avoid proprietary or language-specific solutions&lt;/h2&gt;
&lt;p&gt;TODO: Give preference to common network based APIs&lt;/p&gt;
&lt;h2&gt;Understand the Single Responsibility Principle (SRP)&lt;/h2&gt;
&lt;p&gt;TODO: you can apply or not but it&amp;#39;s important to understand it&lt;/p&gt;
&lt;h2&gt;Don&amp;#39;t bother too much about the Open/Closed Principle (OCP)&lt;/h2&gt;
&lt;p&gt;TODO: explain differences between writing end-software and libraries and talk about tests here&lt;/p&gt;
&lt;h2&gt;Take decisions by yourself (avoid just following well-stablished patterns)&lt;/h2&gt;
&lt;p&gt;TODO: talk about Java, setters/getters, private/protected/public, interfaces and its abuse&lt;/p&gt;
&lt;h2&gt;Use dependency-resolving tools&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Use the best VCS tool you can find&lt;/h2&gt;
&lt;p&gt;TODO: and invest time learning it&lt;/p&gt;
&lt;h2&gt;Coding style examples&lt;/h2&gt;
&lt;h3&gt;Early interruption pattern (or handle exceptions first)&lt;/h3&gt;
&lt;p&gt;TODO: return if exceptional_case&lt;/p&gt;
&lt;h3&gt;Don&amp;#39;t handle exceptions at all if possible&lt;/h3&gt;
&lt;p&gt;TODO: talk about the try-catch approach and the type of applications (libraries, unsaved data) as well as about tests.&lt;/p&gt;
&lt;h3&gt;Don&amp;#39;t catch each exception for general algorithm&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h3&gt;Avoid deeply nested constructions&lt;/h3&gt;
&lt;p&gt;TODO: talk about nested if&amp;#39;s, while&amp;#39;s and alternatives like catch-throw&lt;/p&gt;
&lt;h3&gt;Sort method caveat&lt;/h3&gt;
&lt;p&gt;TODO: talk about &amp;lt;=&amp;gt; and how to deal with its lack in some languages. Sort should return -1, 0 or 1.
TODO: talk about wrong usage of sort for getting max and min.&lt;/p&gt;
&lt;h3&gt;Switch-case and handling by hashes (or maps)&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Security concerns&lt;/h2&gt;
&lt;h3&gt;Mass-assignment&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Multi-threading&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h3&gt;Java specifics&lt;/h3&gt;
&lt;p&gt;TODO: talk about synchronized methods&lt;/p&gt;
&lt;h2&gt;Performance and Scalability&lt;/h2&gt;
&lt;p&gt;TODO: talk about language vs architecture, and concerning before due time or without benchmark/profiling.&lt;/p&gt;
&lt;p&gt;TODO: talk about simple web APIs and queuing systems for integrating applications in possibly different languages.
TODO: Avoid writing language or vendor specific solutions&lt;/p&gt;
&lt;h2&gt;Memory leak&lt;/h2&gt;
&lt;p&gt;TODO: It does happen in Java. Talk about unbounded in-memory cache.&lt;/p&gt;
</content:encoded></item><item><title>The Danger in Software Customization</title><link>https://rosenfeld.page/articles/2011_07_07_the_danger_in_software_customization/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2011_07_07_the_danger_in_software_customization/</guid><pubDate>Thu, 07 Jul 2011 23:40:00 GMT</pubDate><content:encoded>&lt;div class=&quot;centralizado&quot;&gt;&lt;img alt=&quot;Overdesigned swiss knife&quot; src=&quot;http://s3.amazonaws.com/site_rosenfeld/gig-swiss-knife.jpg&quot; /&gt;&lt;/div&gt;

&lt;p&gt;Several years ago, one of the partners of a company I worked for, commented the following with me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In USA, people tend to adapt their work-flow to the software they use. In Brazil, we always
want to adapt the software to our needs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He was actually complaining about the way we Brazilians behave regarding software adaptation vs
software customization. And I mostly agree with him that we Brazilians really do that while
there are several situations where it would be much simpler (meaning less cost) if people could
just adapt themselves to the way the software already works. I can&amp;#39;t speak for people in USA though,
since I don&amp;#39;t really know them enough! :)&lt;/p&gt;
&lt;p&gt;Martin Fowler also wrote &lt;a href=&quot;http://martinfowler.com/bliki/PackageCustomization.html&quot;&gt;great&lt;/a&gt;
&lt;a href=&quot;http://martinfowler.com/bliki/UtilityVsStrategicDichotomy.html&quot;&gt;articles&lt;/a&gt; on the subject.&lt;/p&gt;
&lt;p&gt;In this article, I&amp;#39;ll present my thoughts on what this means for those working on this customizations.&lt;/p&gt;
&lt;p&gt;Jason Fried and David Heinemeier Hansson, founders of 37signals, also talked about this subject in
their (recommended) book &lt;em&gt;Rework&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Build half a product, not a half-assed product&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some ideas are really great and powerful.&lt;/p&gt;
&lt;div class=&quot;centralizado&quot;&gt;&lt;img alt=&quot;Amphibious Car&quot; src=&quot;http://s3.amazonaws.com/site_rosenfeld/amphibious-car.jpg&quot; /&gt;&lt;/div&gt;

&lt;p&gt;But if things go wrong they can become a disaster!&lt;/p&gt;
&lt;div class=&quot;centralizado&quot;&gt;&lt;img alt=&quot;Underwater Amphibious Car&quot; src=&quot;http://s3.amazonaws.com/site_rosenfeld/amphibious-car-underwater.jpg&quot; /&gt;&lt;/div&gt;

&lt;p&gt;The authors greatly summarized the problem in the topic &amp;quot;Let your customers outgrow you&amp;quot;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;...There&amp;#39;s a customer that&amp;#39;s paying a company a lot of money. The company tries
to please that customer in any way possible... Then one day that big customer
winds up leaving and the company is left holding the bag - and the bag is a
product that&amp;#39;s ideally suited to someone who&amp;#39;s not there anymore. And now it&amp;#39;s
a bad fit for everyone else.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They also give great advices like &amp;quot;Say no by default&amp;quot;.&lt;/p&gt;
&lt;p&gt;This is really important because it is so easy to say yes as it is ineffective.
A good manager is that one that is able to understand a &amp;quot;no&amp;quot; suggestion from 
developers and convince their client to accept the &amp;quot;no&amp;quot; too.&lt;/p&gt;
&lt;p&gt;There are lots of situations where we just want some change because we don&amp;#39;t
want to change ourselves. Think in about how much developers still use a
centralized version control system like Subversion or CVS just because they
don&amp;#39;t want to learn how distributed VCS like Git and Mercurial work.
Think how much they lose by choosing to not change their minds.&lt;/p&gt;
&lt;p&gt;The decisions around customization should be well thought. Not all customizations
are worth. If you have a product that is shared among some clients, all of them
having some different requirements, you shouldn&amp;#39;t agree delivering every requested
feature.&lt;/p&gt;
&lt;img alt=&quot;Underwater Amphibious Car&quot; src=&quot;http://s3.amazonaws.com/site_rosenfeld/plugin.jpg&quot; style=&quot;float: right; margin: 2em&quot; /&gt;

&lt;p&gt;As a rule of thumb, I would ask myself some simple questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is that change something that could be implemented as some sort of a plug-in?&lt;/li&gt;
&lt;li&gt;Is that change really useful, including for the client who is asking for it?&lt;/li&gt;
&lt;li&gt;Will the other clients use that feature?&lt;/li&gt;
&lt;li&gt;Is it easy to isolate it and add some software switch for enabling/disabling that feature?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these questions can be answered affirmatively, then it probably worths
implement the feature. Of course, the effort/cost vs goodies should be measured as well.&lt;/p&gt;
&lt;img alt=&quot;An electric outlet over a pool supported by sandals&quot; src=&quot;http://s3.amazonaws.com/site_rosenfeld/pool-and-electric-outlet.jpg&quot; style=&quot;float: left; clear: before; margin: 2em&quot; /&gt;

&lt;p&gt;In the other side, you should probably say &amp;quot;no&amp;quot; to your clients if the change implies in either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There will be a substantial change to your system, increasing the risk of failures.
This is specially true if the application doesn&amp;#39;t rely on a good test suite or if it is
a critical application.&lt;/li&gt;
&lt;li&gt;Adding such a feature means that you&amp;#39;ll need several conditionals among all over the code.&lt;/li&gt;
&lt;li&gt;Accepting the change means that any future change would become much slower to achieve.&lt;/li&gt;
&lt;li&gt;Implementing the change will make it much harder to get some reports from the system and/or
will make the report generation or interface navigation time much slower.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I guess there will be a gray shadow between these lines, but the main problem is that
most people I worked with in my life simply will never consider saying &amp;quot;no&amp;quot; at all. They
say it is just a matter of money vs time needed to accomplish it. But usually they&amp;#39;re not
able to really estimate the costs of such a bad decision in the long run.&lt;/p&gt;
&lt;p&gt;I wonder if Brazilians will change their mind some day and start to evaluate adapting
themselves to some software or process sometimes instead of insisting in customizations.
I also wonder if they&amp;#39;ll learn to negotiate better the features instead of just accepting
the requirements as they are. I hope so, but I don&amp;#39;t really believe it will happen any
time soon...&lt;/p&gt;
</content:encoded></item><item><title>Installing Gitorious has never been so easy</title><link>https://rosenfeld.page/articles/2011_03_06_installing_gitorious_has_never_been_so_easy/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2011_03_06_installing_gitorious_has_never_been_so_easy/</guid><pubDate>Sun, 06 Mar 2011 20:40:00 GMT</pubDate><content:encoded>&lt;h2&gt;Important update (May 07, 2011)&lt;/h2&gt;
&lt;p&gt;This article explains how to install Gitorious using RVM Ruby on Nginx + Passenger. I&amp;#39;ve recently created another cookbook for installing Gitorious on a recent Debian using native Ruby as well as Apache2 and using Exim as a smarthost for sending e-mail, which means that Gitorious won&amp;#39;t block waiting the SMTP server for replying (specially if internet or the mail server is down). Also, this new cookbook will install much faster (less than 15 minutes in my PC). Feel free to continue reading this article if you want Gitorious with RVM Ruby. Otherwise, I would recommend the &lt;a href=&quot;https://github.com/rosenfeld/gitorious-cookbooks&quot;&gt;new cookbook&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: if you just want to install Gitorious, feel free to jump to &lt;a href=&quot;#installing&quot;&gt;Installing Gitorious section&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Installing Gitorious is HARD&lt;/h2&gt;
&lt;p&gt;Installing Gitorious is one of the most time-consuming servers to set-up I&amp;#39;ve seen. And I&amp;#39;m a Rails developer.&lt;/p&gt;
&lt;p&gt;Installing the Rails application itself was not trivial as it should in the first time I set up a Gitorious server, some years ago. The usual &amp;quot;rake gems:install&amp;quot; procedure of the Rails 2 era didn&amp;#39;t work and we had to follow the instructions, often outdated, of which gems we should install manually with all the problems it brings as version compatibility issues. Fortunately, the Ruby community brought Bundler some time ago which changed this painful process completely making it a breeze to manage Ruby project dependencies.&lt;/p&gt;
&lt;p&gt;The good news is that Gitorious recently started to use bundler for managing its dependencies. So, installing the Rails application became trivial. But setting the web application itself was never the most time consuming task. Far from it. The Gitorious overall system uses a mixin of technologies including the web server, memcached for dealing with cache, a stomp server, like ActiveMQ, for managing queues of jobs like creating or cloning repositories, Sphinx for searching in the projects and repositories, a MySQL database for storing data, an HTTP server like Apache or Nginx plus Passenger, several custom services for serving the Git protocol with some changes from the original &amp;quot;git daemon&amp;quot;, etc. Additionally, there are lots of configurations for e-mail delivery, SSH and the web application itself.&lt;/p&gt;
&lt;p&gt;Some impatient people or with not enough skill often gave up on setting up a private Gitorious server for their companies. Others will successfully set-up after a whole day or two. If you&amp;#39;re feeling adventurous or are just curious about how Gitorious work, try to follow &lt;a href=&quot;http://cjohansen.no/en/ruby/setting_up_gitorious_on_your_own_server&quot;&gt;these instructions&lt;/a&gt; or read the documentation present on Gitorious mainline repository.&lt;/p&gt;
&lt;h2&gt;This is no more true - Chef to the rescue&lt;/h2&gt;
&lt;p&gt;Well, I didn&amp;#39;t mind very much that setting up a Gitorious was a hard task since I just needed to set it up once some years ago and another time when another developers team asked me about an year later. It is working great for us for a long time.&lt;/p&gt;
&lt;p&gt;These days I decided that I should finally play a bit with &lt;a href=&quot;http://www.opscode.com/chef/&quot;&gt;Chef&lt;/a&gt;, a configuration management system. Nothing better than a real complex case to learn a new tool. Than I chose Gitorious for learning Chef. After 2 days (about 4hs/day) learning about Chef and writing the Gitorious cookbook, I found that &lt;a href=&quot;https://github.com/fnichol/chef-gitorious&quot;&gt;Fletcher Nichol already had written one&lt;/a&gt;. I threw away almost all I had already done and continued from his work, since it didn&amp;#39;t work on a fresh Debian 6.0 (Squeeze) system.&lt;/p&gt;
&lt;p&gt;The result is a really easy process to install Gitorious on a fresh Debian system.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;installing&quot; style=&quot;color: black&quot;&gt;Installing Gitorious&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If something documented here goes wrong, go bug Fletcher Nichol, since he is the original author of the Chef cookbooks ;) Just kidding! He did an awesome work, but feel free to post me a message if you have any issues.&lt;/p&gt;
&lt;p&gt;These instructions are known to work on a Debian Squeeze 6.0 Linux distribution with only the base system checked to install on package selection. You can install it with VirtualBox, for instance, using the &amp;quot;netinst&amp;quot; CD image, which can be downloaded &lt;a href=&quot;http://www.debian.org/CD/netinst/&quot;&gt;here&lt;/a&gt; or from &lt;a href=&quot;http://www.debian.org/CD/http-ftp/&quot;&gt;some mirror near you&lt;/a&gt;. You&amp;#39;ll need at least 1GB of virtual memory (I would suggest 512MB of physical memory plus 512MB of swap for a local testing only environment) and 4GB of hard-disk (maybe 3GB will be enough). I recommend you to use LVM since it is easier to expand your partitions if you need later. You can use a single partition if you prefer. If you are using VirtualBox, you&amp;#39;ll probably like to set the network to bridge mode so that you can connect to your VM from your host machine. When asked for the machine name, if you don&amp;#39;t have a fully qualified domain name (FQDN), you can use &amp;quot;gitorious.local&amp;quot;.&lt;/p&gt;
&lt;p&gt;Don&amp;#39;t create a &amp;quot;git&amp;quot; user, since Chef will already create it correctly for you. If you need help creating the bridge network on Debian, &lt;a href=&quot;http://wiki.debian.org/BridgeNetworkConnections&quot;&gt;check out these instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the fresh Debian system installed, logged as root:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;echo &amp;#39;deb http://apt.opscode.com/ squeeze main&amp;#39; &amp;gt; /etc/apt/sources.list.d/opscode.list
wget -qO - http://apt.opscode.com/packages@opscode.com.gpg.key | apt-key add -
apt-get update
apt-get install chef git
wget -O /etc/chef/solo.rb https://gist.github.com/raw/847256/chef-gitorious-etc-solo.rb
mkdir /root/chef-solo
wget -O /root/chef-solo/node.json https://gist.github.com/raw/847256/chef-gitorious-node.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Change your /root/chef-solo/node.json to reflect your Gitorious settings, like SMTP server, etc. The downloaded node.json will download Gitorious from my fork, which includes a tree source view to Gitorious (see &lt;a href=&quot;http://gitorious.org/gitorious/mainline/merge_requests/2220&quot;&gt;Merge Request #2220&lt;/a&gt;), as you can see in the picture below. Feel free to remove the &amp;quot;git&amp;quot; parameter from the &amp;quot;gitorious&amp;quot; entry and it will use the vanilla Gitorious repository. Also note that &amp;quot;locale&amp;quot; is set to &amp;quot;pt-BR&amp;quot;. Change it to &amp;quot;en&amp;quot; or choose one of &amp;quot;pt-BR&amp;quot;, &amp;quot;es&amp;quot; or &amp;quot;fr&amp;quot;. I can tell you &amp;quot;en&amp;quot; and &amp;quot;pt-BR&amp;quot; will work but I haven&amp;#39;t tested the other ones. If you change the &amp;quot;web_server&amp;quot; attribute to &amp;quot;apache2&amp;quot;, you&amp;#39;ll be on your own and you&amp;#39;ll probably have to tweak it yourself.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://s3.amazonaws.com/site_rosenfeld/gitorious-snapshot.png&quot;&gt;&lt;img alt=&quot;Gitorious snapshot with source tree view&quot; src=&quot;http://s3.amazonaws.com/site_rosenfeld/gitorious-snapshot.png&quot; style=&quot;width: 100%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &amp;quot;run_list&amp;quot; only needs to contain &amp;quot;recipe[gitorious]&amp;quot;. The other ones are optional.&lt;/p&gt;
&lt;p&gt;After changing the settings to reflect your preferences proceed with Gitorious automated installation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;git clone git://github.com/rosenfeld/cookbooks.git /root/chef-solo/cookbooks
cd /root/chef-solo/cookbooks
git submodule update --init
chef-solo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don&amp;#39;t have a FQDN nor a local DNS server, you can add your machine IP to your /etc/hosts on your host system. You need to access Gitorious with the FQDN provided in /root/chef-solo/node.json, which defaults to &amp;quot;gitorious.local&amp;quot;, or the web application won&amp;#39;t work.&lt;/p&gt;
&lt;p&gt;Following these instructions, I was able to install Debian in 10 minutes and Gitorious within an extra hour. The actual time will depend mainly on your internet speed as well as your CPU and how many cores you&amp;#39;ll make available for your VM. Maybe it is a good idea to allocate more resources to your VM on the installation process and then you could reduce them. There are several techniques that could speed up this installation process, like doing some tasks in parallel, using multiple cores on the VMs, using Debian Ruby instead of RVM, replacing ActiveMQ with stompserver gem, among other things. But this is beyond the scope of this article. I guess installing gitorious on a real fast server with great band-width could take about 20 minutes using these instructions. But since this process is automated, you can use this installation time to &lt;a href=&quot;/en/articles/2010-12-26-achieving-productivity-with-vim-as-ide&quot;&gt;learn how to become productive with Vim&lt;/a&gt; :)&lt;/p&gt;
&lt;p&gt;Simple, right? Get in touch if you have any issues.&lt;/p&gt;
&lt;p&gt;Good luck! ;)&lt;/p&gt;
&lt;h2&gt;Thanks&lt;/h2&gt;
&lt;p&gt;Thanks go to many people who made this possible, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fnichol&quot;&gt;Fletcher Nichol&lt;/a&gt; who developed the original Gitorious, RVM and RVM_Passenger cookbooks;&lt;/li&gt;
&lt;li&gt;Opscode and Chef community for making this automated stuff possible;&lt;/li&gt;
&lt;li&gt;The Gitorious developers and contributers;&lt;/li&gt;
&lt;li&gt;David Heinemeier Hansson (DHH) for creating the fabulous Rails framework and all other rails-core team members as well as its contributors;&lt;/li&gt;
&lt;li&gt;Yehuda Katz and all Bundler developers;&lt;/li&gt;
&lt;li&gt;Yukihiro Matsumoto (Matz) and all Ruby developers and contributors for the lovely programming language they created and maintain;&lt;/li&gt;
&lt;li&gt;Wayne Seguin for the excelent RVM tool and all of its contributors;&lt;/li&gt;
&lt;li&gt;The Debian community for the wonderful Linux distribution;&lt;/li&gt;
&lt;li&gt;Sun (recently sold to Oracle) for the great VirtualBox for managing virtual machines and all its contributors;&lt;/li&gt;
&lt;li&gt;The Phusion company for delivering Passenger, easing the deployment of Rails and Rack applications;&lt;/li&gt;
&lt;li&gt;Linus Torvalds, of course, not only for having started the Linux kernel development, but specially for the development of the greatest version control system: Git. Thanks also goes to Junio Hamano and the other Git developers and contributors;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are probably lots more to thank and it is impressive how much people and work were required before one could easily install Gitorious for her/his company intranet. :)&lt;/p&gt;
</content:encoded></item><item><title>Achieving Productivity with Vim as IDE</title><link>https://rosenfeld.page/articles/2010_12_26_achieving_productivity_with_vim_as_ide/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2010_12_26_achieving_productivity_with_vim_as_ide/</guid><pubDate>Fri, 10 Sep 2010 20:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Finally I&amp;#39;ve got some time to finish translating my Vim original article in Portuguese (written in September/2010):&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve long insisted on trying to use Java written IDEs like Netbeans, RubyMine, Aptana/Eclipse or IntelliJ IDEA
for software developing. They are fine except that they use too much system resources and you never know when the
next garbage collection will happen (usually in the greatest inspiration moment).&lt;/p&gt;
&lt;p&gt;I was so upset with memory usage (my 4GB RAM computer was swapping very often) and garbage collection that I decided
to take 3 full days of my last holiday to learn how to get productivity with Vim. The result was good enough and here
is the summary of what I could get from Vim and what I could not.&lt;/p&gt;
&lt;p&gt;Note 1: if you are already a Vim user, backup your configuration files before trying this setup.
Note 2: I would like to thank &lt;a href=&quot;http://www.linkedin.com/groups?viewMemberFeed=&amp;gid=22413&amp;memberID=81276429&quot;&gt;Michael Durrant&lt;/a&gt;
and Vim spelling support for &lt;a href=&quot;http://www.linkedin.com/groupAnswers?viewQuestionAndAnswers=&amp;discussionID=28872877&amp;gid=22413&amp;commentID=22685243&amp;trk=view_disc&quot;&gt;helping with translation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What to expect?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Light speed!&lt;/li&gt;
&lt;li&gt;Auto-complete (with current setup, works well for HTML, CSS, XML, leaving the desire for others IDEs for Java)&lt;/li&gt;
&lt;li&gt;Snippets&lt;/li&gt;
&lt;li&gt;Tabbed editing&lt;/li&gt;
&lt;li&gt;Recording Session&lt;/li&gt;
&lt;li&gt;Auto-completion of words contained in the document &lt;/li&gt;
&lt;li&gt;Support for browsing RDoc (Ruby) &lt;/li&gt;
&lt;li&gt;File browser &lt;/li&gt;
&lt;li&gt;Fast file opening&lt;/li&gt;
&lt;li&gt;View number of rows and &amp;quot;go to line n&amp;quot;; &lt;/li&gt;
&lt;li&gt;Switch to the definition of the class / method / tag under the cursor &lt;/li&gt;
&lt;li&gt;Spell check (getting spelling support for Netbeans was really hard when I tried to, while it is built-in for Vim 7 and easy to add new dictionaries)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to these features, I&amp;#39;ve got much more ones that I&amp;#39;ve never used on my prior IDEs experience, as shown in this article.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;Here are the install procedures tested on a Debian Unstable Linux distribution that should work almost seamless with Ubuntu too. In Windows,
apparently the change is that the configuration directory of Vim is called &amp;quot;vimfiles&amp;quot; instead of &amp;quot;.vim&amp;quot;. If you have any questions about the
installation process, just post a comment.&lt;/p&gt;
&lt;p&gt;You need to be root (or use sudo in Ubuntu) for installing the required packages.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;apt-get install exuberant-ctags vim-gtk git
cd
git clone --recursive git://github.com/rosenfeld/vimfiles.git .vim
ln -s .vim/vimrc .vimrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some additional notes in case you have any issues with the above steps or are just curious:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you further install gitk and git-gui, there are shortcuts for launching them from Vim.&lt;/li&gt;
&lt;li&gt;Gnome users might prefer installing vim-gnome instead of vim-gtk. Some shortcuts (like Ctrl+S)
won&amp;#39;t work on Vim when running in some terminal emulator as Konsole or gnome-terminal because they will capture the shortcuts before Vim can
handle them and gVim is recommended instead.&lt;/li&gt;
&lt;li&gt;The exuberant-ctags package is required for tag navigation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Features&lt;/h2&gt;
&lt;p&gt;Vim has much more features than what I&amp;#39;ll introduce on this article. I would suggest reading other resources on the subject if you have some free time.&lt;/p&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;h4&gt;Editing, saving, navigation and quiting&lt;/h4&gt;
&lt;p&gt;Unlike other editors, Vim has different modes. It starts in Normal mode, in which typed chars are interpreted as commands. Pressing &amp;#39;i&amp;#39; or &amp;#39;Insert&amp;#39;,
enter Vim in insert mode, from which you can type anything. To exit insert mode, just press &amp;#39;Escape&amp;#39;.&lt;/p&gt;
&lt;p&gt;Most commands are available through a command line that shows up when a colon (&amp;#39;:&amp;#39;) is pressed. Some of them are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;:q&amp;#39;: Quit without saving. Vim will warn you instead of leaving when any changes are unsaved.&lt;/li&gt;
&lt;li&gt;&amp;#39;:w&amp;#39;: Write buffer to current file (save the file).&lt;/li&gt;
&lt;li&gt;&amp;#39;Ctrl+x, s&amp;#39;: Save current file, while on Insert mode.&lt;/li&gt;
&lt;li&gt;&amp;#39;:x&amp;#39; or &amp;#39;:wq&amp;#39; or &amp;#39;ZZ&amp;#39;: Quit saving changes.&lt;/li&gt;
&lt;li&gt;&amp;#39;:q!&amp;#39;: Quit discarding changes.&lt;/li&gt;
&lt;li&gt;&amp;#39;:qa&amp;#39;: Quit closing all buffers (read &amp;quot;files&amp;quot;, for simplicity sake). Actually, prior commands will only act on current buffer.&lt;/li&gt;
&lt;li&gt;&amp;#39;:e path/to/file&amp;#39;: Open file in the current window (auto-complete is achieved with the TAB key). If a relative path is given,
the current Vim directory (&amp;#39;:pwd&amp;#39; will show it) is used. This can be changed with the &amp;#39;:cd /new/path&amp;#39; command or &amp;#39;:lcd&amp;#39; for
changing the path just for current window (more on windows later).&lt;/li&gt;
&lt;li&gt;&amp;#39;,f path/relative/to/file&amp;#39;: &amp;#39;,f&amp;#39; expands current file path and puts you on the command line&lt;/li&gt;
&lt;li&gt;&amp;#39;:tabe&amp;#39; and &amp;#39;,t&amp;#39;: the same thing bug open file in a tab instead of the current window.&lt;/li&gt;
&lt;li&gt;&amp;#39;Ctrl+PageUp/PageDown&amp;#39;: navigate through tabs (may not work on terminal Vim)&lt;/li&gt;
&lt;li&gt;&amp;#39;:tabnew&amp;#39;: Open an empty buffer on a new tab&lt;/li&gt;
&lt;li&gt;&amp;#39;:e!&amp;#39;: Discard file changes and load last saved content&lt;/li&gt;
&lt;li&gt;&amp;#39;w&amp;#39;: Position the cursor to the beginning of next word&lt;/li&gt;
&lt;li&gt;&amp;#39;e&amp;#39;: Position the cursor to the end of next word&lt;/li&gt;
&lt;li&gt;&amp;#39;b&amp;#39;: Position the cursor backward to the beginning of the word&lt;/li&gt;
&lt;li&gt;&amp;#39;,w&amp;#39; and &amp;#39;,b&amp;#39;: The same considering CamelCase words&lt;/li&gt;
&lt;li&gt;&amp;#39;0&amp;#39;: Position the cursor at start of current line&lt;/li&gt;
&lt;li&gt;&amp;#39;^&amp;#39;: Position the cursor at the first non-blank character of the current line&lt;/li&gt;
&lt;li&gt;&amp;#39;$&amp;#39;: Position the cursor at the end of the line&lt;/li&gt;
&lt;li&gt;&amp;#39;%&amp;#39;: Go to the corresponding pair of &amp;#39;[]&amp;#39;, &amp;#39;()&amp;#39; and &amp;#39;{}&amp;#39;&lt;/li&gt;
&lt;li&gt;&amp;#39;gg&amp;#39;: Go to the beginning of current buffer (document)&lt;/li&gt;
&lt;li&gt;&amp;#39;G&amp;#39;: Go to the end of buffer&lt;/li&gt;
&lt;li&gt;&amp;#39;45G&amp;#39;: Go to line 45&lt;/li&gt;
&lt;li&gt;&amp;#39;~&amp;#39;: Change the case of the letter under cursor&lt;/li&gt;
&lt;li&gt;&amp;#39;u&amp;#39;: Undo&lt;/li&gt;
&lt;li&gt;&amp;#39;Ctrl-r&amp;#39;: Redo&lt;/li&gt;
&lt;li&gt;&amp;#39;.&amp;#39;: repeat last command&lt;/li&gt;
&lt;li&gt;&amp;#39;J&amp;#39;: join lines&lt;/li&gt;
&lt;li&gt;Ctrl+e: scrolls one line down without moving the cursor&lt;/li&gt;
&lt;li&gt;Ctrl+y: scrolls one line up without moving the cursor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On insert/editing mode, you can call normal mode commands by pressing Ctrl+O before the command. While on
normal mode, it is possible to change to insert mode using some commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;i: doesn&amp;#39;t change current cursor position&lt;/li&gt;
&lt;li&gt;I: position the cursor in the beginning of the line&lt;/li&gt;
&lt;li&gt;o: appends a new line below the current line&lt;/li&gt;
&lt;li&gt;O: appends a new line above the current line&lt;/li&gt;
&lt;li&gt;a: position the cursor one character after current cursor position&lt;/li&gt;
&lt;li&gt;A: position the cursor at the end of current lines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Commands for deleting lines, words, blocks, managing surrounds and toggling comments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dd: delete current line (actually, moves it to Vim internal clipboard)&lt;/li&gt;
&lt;li&gt;D: delete until the end of the line&lt;/li&gt;
&lt;li&gt;x or Delete: deletes a character under cursor&lt;/li&gt;
&lt;li&gt;Backspace: deletes a character backward&lt;/li&gt;
&lt;li&gt;dw: delete from current cursor until the end of the word under cursor&lt;/li&gt;
&lt;li&gt;diw: delete inner word (the entire word under the cursor)&lt;/li&gt;
&lt;li&gt;db: delete until the beginning of the word or a word backward if the cursor is already in the beginning of some word&lt;/li&gt;
&lt;li&gt;ds&amp;#39;, ds&amp;quot;, ds{, ds[, ds(: delete surrounds (&amp;#39;&amp;#39;, &amp;quot;&amp;quot;, {}, (), [])&lt;/li&gt;
&lt;li&gt;dst: delete surrounding tag&lt;/li&gt;
&lt;li&gt;di&amp;#39;, di&amp;quot;, di{, di[, di(: delete content inside the given surround&lt;/li&gt;
&lt;li&gt;da&amp;#39;, da&amp;quot;, da{, da[, da(: delete all content of the given surround, including the surround characters&lt;/li&gt;
&lt;li&gt;dit: delete inner tag content&lt;/li&gt;
&lt;li&gt;cs*: works like ds*, but replacing the surround instead of deleting them. For instance, ci&amp;quot;&amp;#39; will turn &amp;quot;text&amp;quot; into &amp;#39;text&amp;#39;.
ci&amp;quot;t&amp;lt;div&amp;gt; will result in &amp;lt;div&amp;gt;text&amp;lt;/div&amp;gt;...&lt;/li&gt;
&lt;li&gt;yss*: apply surround around the entire line. Ex.: yss&amp;#39; will apply an apostrophe around the line, while yss&amp;lt;div&amp;gt; will surround the line with a div tag.&lt;/li&gt;
&lt;li&gt;s*: adds a surround while on visual mode (click and drag with mouse or press &amp;#39;v&amp;#39; to ender visual mode and use the movement commands)&lt;/li&gt;
&lt;li&gt;ys&amp;lt;movement command&amp;gt;: applies surround around the region described by the movement command. Ex.: With cursor under &amp;quot;word&amp;quot; ysiw&amp;lt;span&amp;gt; results in &amp;lt;span&amp;gt;word&amp;lt;/span&amp;gt;&lt;/li&gt;
&lt;li&gt;C, cw, ciw, cb, ci*, etc: Works like the delete commands but finish the command on insert mode (c stands for change)&lt;/li&gt;
&lt;li&gt;gv: Reselect last visual selection&lt;/li&gt;
&lt;li&gt;\c&amp;lt;space&amp;gt;: toggle line (or block in visual mode) commenting&lt;/li&gt;
&lt;li&gt;ggdG: [d]eletes entire buffer - from beginning [gg] to end [G] of the document&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Copy and paste&lt;/h4&gt;
&lt;p&gt;In normal mode (don&amp;#39;t use &amp;#39;:&amp;#39;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;yy: copy (yank) current line to clipboard&lt;/li&gt;
&lt;li&gt;p: paste content from clipboard&lt;/li&gt;
&lt;li&gt;yyp: duplicate current line&lt;/li&gt;
&lt;li&gt;&amp;#39;:%y&amp;#39;: copy the whole buffer (document) for internal use in Vim, only&lt;/li&gt;
&lt;li&gt;&amp;#39;:%y+&amp;#39;: copy the whole document to system clipboard&lt;/li&gt;
&lt;li&gt;&amp;#39;:%y*&amp;#39;: the * register is a clipboard register associated with the middle button on *nix systems. This command copies the document to this clipboard area.&lt;/li&gt;
&lt;li&gt;&amp;quot;+yy (or Ctrl+X, c): copy current line to the system clipboard (register +)&lt;/li&gt;
&lt;li&gt;&amp;quot;*yy: copy current line to the middle-click associated clipboard (register *)&lt;/li&gt;
&lt;li&gt;Ctrl+R,+ (ou Ctrl+X, v) e Ctrl+R * (ou Ctrl+X, b): paste from system clipboard and middle-click clipboard respectively&lt;/li&gt;
&lt;li&gt;Ctrl+C: In visual mode, copy selection to system clipboard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In visual mode, &amp;#39;y&amp;#39; copies the selection, while &amp;#39;&amp;quot;+y&amp;#39; / &amp;#39;&amp;quot;*y&amp;#39; copy the content to registers + and *.&lt;/p&gt;
&lt;h3&gt;Windows and Tabs&lt;/h3&gt;
&lt;p&gt;I&amp;#39;ve already commented about basic tabs-related commands. Further commands follow below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+w, s: (Press Ctrl+w, then &amp;#39;s&amp;#39;) - split window horizontally&lt;/li&gt;
&lt;li&gt;Ctrl+w, v: (Press Ctrl+w, then &amp;#39;v&amp;#39;) - split window vertically&lt;/li&gt;
&lt;li&gt;Ctrl+w, c: Close current buffer or tab if has a single window&lt;/li&gt;
&lt;li&gt;Ctrl+w, o: Keep Only current window on tab, closing the others&lt;/li&gt;
&lt;li&gt;Ctrl+w, w: Alternate to next window&lt;/li&gt;
&lt;li&gt;Ctrl+w, arrow key: Alternate to window pointed by the arrow key&lt;/li&gt;
&lt;li&gt;Ctrl+w, T: Note the capital T. Move current buffer to a new tab&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Quick file open&lt;/h3&gt;
&lt;p&gt;The &amp;#39;&amp;lt;c-x&amp;gt;&amp;lt;c-f&amp;gt;&amp;#39; (Ctrl+X Ctrl+F) shortcut activates the quick open file dialog.&lt;/p&gt;
&lt;p&gt;Vim will list files in your current dir (launch &amp;#39;:pwd&amp;#39; command to see what is it and &amp;#39;:cd ~/new/path&amp;#39; to change to a new path).
While you type, files are filtered considering the typed expression. For instance, &amp;#39;a/c/uc&amp;#39; will list &amp;#39;app/controllers/user_controller.rb&amp;#39; as an option.&lt;/p&gt;
&lt;p&gt;Hit Enter to open the file in the current buffer. Ctrl+t will open it in a new tab. Ctrl+Enter will open in a new window.&lt;/p&gt;
&lt;h3&gt;Snippets&lt;/h3&gt;
&lt;p&gt;Snippets are expanded with the TAB key. For instance, div&amp;lt;TAB&amp;gt; will expand to &amp;lt;div id=&amp;quot;?&amp;quot;&amp;gt;?&amp;lt;/div&amp;gt;.&lt;/p&gt;
&lt;p&gt;The bundled snippets are located in ~/.vim/bundle/snipmate/snippets and ~/.vim/bundle/rosenfeld/snippets.&lt;/p&gt;
&lt;p&gt;Feel free to modify them and include new ones on bundle/*/snippets and ~/.vim/snippets.&lt;/p&gt;
&lt;h3&gt;Editing HTML, XML, ERB, ASP, JSP, PHP, GSP, etc&lt;/h3&gt;
&lt;p&gt;Shortcuts for working with HTML/XML also work on PHP, ASP, ERB, JSP, etc, once the file type is properly configured like &amp;quot;html.erb&amp;quot;.
This can be achieved with command &amp;quot;:set ft=html.erb&amp;quot;, for ERB files, for instance. You can also set these associations automatically
according to file extension. See some examples in ~/.vim/filetype.vim.&lt;/p&gt;
&lt;p&gt;Some shortcuts for working on HTML have been already discussed. Here are some more shorcuts, for being used on insert mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+x, /: Closes the last open tag.&lt;/li&gt;
&lt;li&gt;Ctrl+x, space: convert word in a tag and put the cursor inside it. Ex.: div&amp;lt;C-x&amp;gt;&amp;lt;space&amp;gt; results in &amp;lt;div&amp;gt;|&amp;lt;/div&amp;gt;, where &amp;#39;|&amp;#39; denotes the final cursor position&lt;/li&gt;
&lt;li&gt;Ctrl+x, Enter: similar to prior command, but with a line break between the tag start and its end&lt;/li&gt;
&lt;li&gt;Ctrl+x, &amp;#39;: creates to a comment tag&lt;/li&gt;
&lt;li&gt;Ctrl+x, &amp;quot;: comment current line&lt;/li&gt;
&lt;li&gt;Ctrl+x, !: open a menu with DOCTYPE choices to choose from to insert on document&lt;/li&gt;
&lt;li&gt;Ctrl+x, @: inserts a stylesheet tag&lt;/li&gt;
&lt;li&gt;Ctrl+x, #: inserts a meta tag with charset=utf8&lt;/li&gt;
&lt;li&gt;Ctrl+x, $: inserts a script tag for the Javascript language&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For template files, like ERB, JSP, PHP, etc:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+x, =: &amp;lt;%= | %&amp;gt; or the equivalent for the file format&lt;/li&gt;
&lt;li&gt;Ctrl+x, -: &amp;lt;% | %&amp;gt; or the equivalent for the file format&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For ERB (Ruby), I&amp;#39;ve created the following alternative snippets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;re: &amp;lt;%= | %&amp;gt;&lt;/li&gt;
&lt;li&gt;rc: &amp;lt;% | %&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you use KDE, it&amp;#39;s possible to launch kcolorchooser for returning a hex color into the document (a CSS, for instance),
hitting F12. Take a look at ~/.vim/initializers/kcolorchooser-mapping.vim for changing your software of choice.&lt;/p&gt;
&lt;h3&gt;Spelling check&lt;/h3&gt;
&lt;p&gt;Commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;spen: enable spelling check for English&lt;/li&gt;
&lt;li&gt;&amp;#39;:set nospell&amp;#39;: disable spelling check&lt;/li&gt;
&lt;li&gt;z= or right-clicking the word: open a menu with spelling correction suggestions to choose one from&lt;/li&gt;
&lt;li&gt;Ctrl+x, s: the same while on insert mode&lt;/li&gt;
&lt;li&gt;]s: next misspelled word&lt;/li&gt;
&lt;li&gt;[s: prior misspelled word&lt;/li&gt;
&lt;li&gt;zg: add word under cursor as a Good word. The word is added to a local dictionary, which can be configured with the spellfile variable (&amp;quot;:set spellfile=~/.vim/spell/custom&amp;quot;)&lt;/li&gt;
&lt;li&gt;zw: mark word as wrong, commenting it on the spellfile if it already appears there&lt;/li&gt;
&lt;li&gt;zG and zW: the same, but doesn&amp;#39;t persist changes, making them valid only in the current Vim session&lt;/li&gt;
&lt;li&gt;zug, zuw, zuG e zuW: undo related command&lt;/li&gt;
&lt;li&gt;&amp;#39;:spellr&amp;#39;: repeat the replacement done by z= for all matches with the replaced word in the current window&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Tags&lt;/h3&gt;
&lt;p&gt;There are some alternatives for working with tags in Vim:&lt;/p&gt;
&lt;h4&gt;Plugin tag-list&lt;/h4&gt;
&lt;p&gt;Commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F8: Alternate tag window with tags created from current buffer or those found by the following command:&lt;/li&gt;
&lt;li&gt;&amp;#39;:TlistAddFilesRecursive . *.rb *.js&amp;#39;: This creates a tags list for all ruby and javascript files from current project (see :pwd).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Native support integrated to ctags program (provided by exuberant-ctags, for instance)&lt;/h4&gt;
&lt;p&gt;For this to work, you must create a &amp;quot;tags&amp;quot; file in the current directory. Take a look at the output of &amp;quot;ctags --list-languages&amp;quot; to see the supported languages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;ctags -R --languages=Ruby,Javascript
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Groovy is not supported by standard exuberant-ctags, but adding &lt;a href=&quot;https://raw.github.com/gist/2142910/ctags&quot;&gt;this content&lt;/a&gt; to ~/.ctags file seems to work.
You can do that with this command (in Linux or Mac):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;curl https://raw.github.com/gist/2142910/ctags &amp;gt;&amp;gt; ~/.ctags
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, use the following commands for jumping to tag definition of the word under cursor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+] or Ctrl+&amp;lt;LeftMouse&amp;gt; or g&amp;lt;LeftMouse&amp;gt;: jump to definition in current window&lt;/li&gt;
&lt;li&gt;Ctrl+T or Ctrl+&amp;lt;RightMouse&amp;gt; or g&amp;lt;RightMouse&amp;gt;: go back to position before jump&lt;/li&gt;
&lt;li&gt;Ctrl+w, ]: split horizontally and jump to tag definition&lt;/li&gt;
&lt;li&gt;g, Ctrl+] and Ctrl+w, g, ]: presents a list of definitions before jumping if there are multiple definitions&lt;/li&gt;
&lt;li&gt;&amp;#39;:tag TagName&amp;#39;: go to &amp;#39;TagName&amp;#39; tag definition&lt;/li&gt;
&lt;li&gt;&amp;#39;:ts TagName&amp;#39;: open a list with found definitions to choose from&lt;/li&gt;
&lt;li&gt;Ctrl+: go to definition in a new tab&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Indenting&lt;/h3&gt;
&lt;p&gt;Commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;==: indents current line&lt;/li&gt;
&lt;li&gt;=: in visual mode, indents the selected block&lt;/li&gt;
&lt;li&gt;gg=G: go to beginning of the buffer (gg) and indents (=) until the end of buffer (G)&lt;/li&gt;
&lt;li&gt;&amp;lt; and &amp;gt;: indents a block (in visual mode) to left or right. Press &amp;#39;.&amp;#39; to repeat last indenting and &amp;#39;u&amp;#39; to undo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Finding and Replacing&lt;/h3&gt;
&lt;p&gt;Commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F4: replace text in interactive mode&lt;/li&gt;
&lt;li&gt;/search_pattern: Find next match. Examples: &amp;quot;/function&amp;quot; or &amp;quot;/\d\{4}-\d\{2}-\d\{2}&amp;quot; to locate some date like &amp;quot;1981-06-13&amp;quot;&lt;/li&gt;
&lt;li&gt;?search_pattern: Find match backward.&lt;/li&gt;
&lt;li&gt;n: repeat the next &amp;#39;/&amp;#39; or &amp;#39;?&amp;#39; command.&lt;/li&gt;
&lt;li&gt;N: same as &amp;#39;n&amp;#39; but in reverse direction.&lt;/li&gt;
&lt;li&gt;&amp;#39;:%s/text/other/&amp;#39;: Replace &amp;#39;text&amp;#39; by &amp;#39;other&amp;#39; in the whole document (some commands accepts ranges and % stands for the whole
document range - see &amp;#39;:h range&amp;#39;)&lt;/li&gt;
&lt;li&gt;&amp;#39;:s/text/other/&amp;#39;: Replace &amp;#39;text&amp;#39; by &amp;#39;other&amp;#39; in the current line. Actually, any character can be used instead of &amp;#39;/&amp;#39;, like &amp;#39;s.7/11/2010.11/7/2010.&amp;#39;&lt;/li&gt;
&lt;li&gt;&amp;quot;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;s/text/other/&amp;quot;: Replace &amp;#39;text&amp;#39; by &amp;#39;other&amp;#39; in the last visual selection.
&amp;#39;&amp;lt; and &amp;#39;&amp;gt; are the markers for the beginning and ending of the visual selection. Pressing &amp;#39;:&amp;#39; while on visual mode, these markers are
automatically inserted in the command line.&lt;/li&gt;
&lt;li&gt;&amp;amp;: repeat last substitution command&lt;/li&gt;
&lt;li&gt;&amp;#39;:Rgrep word &lt;em&gt;.rb&amp;#39;: search for &amp;#39;word&amp;#39; recursively in all &amp;#39;&lt;/em&gt;.rb&amp;#39; files in the project. The &amp;#39;:vimgrep&amp;#39; command can also be used if the external
programs &amp;#39;grep&amp;#39; and &amp;#39;find&amp;#39; aren&amp;#39;t available but the search will be much slower. There are also other differences - take a look at &amp;#39;:h vimgrep&amp;#39;.
For instance, you can open the file in the matched line by typing &amp;#39;:cc 33&amp;#39; (go to 33th result, numbers are listed with &amp;#39;:cl&amp;#39;). Ex.:
&amp;#39;:vimgrep word **/*.rb&amp;#39;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Markers&lt;/h3&gt;
&lt;p&gt;Commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ma: mark current position in the &amp;#39;a&amp;#39; register. Any letter can be used as a register name.&lt;/li&gt;
&lt;li&gt;&amp;#39;a: go to register &amp;#39;a&amp;#39; mark&lt;/li&gt;
&lt;li&gt;&amp;#39;&amp;#39; (two simple quotes): go to the position before the latest jump&lt;/li&gt;
&lt;li&gt;Ctrl+O, Ctrl+i: go to the prior and next positions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changes list&lt;/h3&gt;
&lt;p&gt;Commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;:changes&amp;#39;: list all changes in the current buffer&lt;/li&gt;
&lt;li&gt;g;: go to the last change&lt;/li&gt;
&lt;li&gt;g,: go to next change&lt;/li&gt;
&lt;li&gt;4g;: go to the change #4 (numbers are displayed by the &amp;#39;:changes&amp;#39; command)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Navigation among buffers&lt;/h3&gt;
&lt;p&gt;Commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+x Ctrl+x: in any mode, opens a window presenting the opened buffers to switch to (press &amp;#39;q&amp;#39; to cancel or &amp;#39;Enter&amp;#39; to choose an option)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;File tree navigation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+n: alternate file navigation window&lt;/li&gt;
&lt;li&gt;\n: the same but expand the tree in the location of the file being currently edited&lt;/li&gt;
&lt;li&gt;&amp;#39;:e.&amp;#39;: replace current window by a file browser starting in the project root, that allows you to choose any file to open in the current window&lt;/li&gt;
&lt;li&gt;&amp;#39;:Ex&amp;#39;: the same but uses the current file path as the start location&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;File tree shortcuts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enter: open the file in a new horizontal split or in the same window if the file is not modified&lt;/li&gt;
&lt;li&gt;t: open in a new tab&lt;/li&gt;
&lt;li&gt;?: list the other shortcuts&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;External commands&lt;/h3&gt;
&lt;p&gt;For running an external command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;:! git gui&amp;amp;&amp;#39;: execute &amp;#39;git gui&amp;#39; in background (doesn&amp;#39;t work on Windows, of course)&lt;/li&gt;
&lt;li&gt;&amp;#39;:.! ls *.txt&amp;#39;: replaces current line with the output of the command &amp;#39;ls *.txt&amp;#39;&lt;/li&gt;
&lt;li&gt;&amp;#39;:+! ls *.txt&amp;#39;: creates a new line below the current line with the output of the command &amp;#39;ls *.txt&amp;#39; (use &amp;#39;-&amp;#39; instead for creating the line above the current line)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Git integration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;\g: Starts the git gui for the current project (doesn&amp;#39;t work on Windows currently). Use &amp;#39;:lcd ~/project/path&amp;#39; for changing the project directory in the current window,
or &amp;#39;:cd&amp;#39; for changing the path for the hole vim session&lt;/li&gt;
&lt;li&gt;\k: Starts gitk in background (doesn&amp;#39;t work on Windows)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See $VIMHOME/bundle/vcscommand/doc/vcscommand.txt for other commands. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;\cd: show the diff for the current file in a new horizontal split&lt;/li&gt;
&lt;li&gt;\cr: review the last committed version of the file in a new window&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Suppose you want to know what are the differences from your current unsaved changes and the original file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;\cr: split the original version in a new horizontal split. If you want the split to be vertical, you can move the window to the left (Ctrl+w, H) or right (Ctrl+w, L).
H and L must be capital.&lt;/li&gt;
&lt;li&gt;run &amp;#39;:diffthis&amp;#39; in both windows: see next topic on diff.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also take a look at $VIMHOME/bundle/fugitive/doc/fugitive.txt for further git shortcuts, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;:Gstatus&amp;#39;: show the output of &amp;#39;git status&amp;#39; and allows you to stage or unstage files under cursor pressing &amp;#39;-&amp;#39;,
or viewing the diff in a vertical window (pressing &amp;#39;D&amp;#39;) or in a horizontal window (pressing &amp;#39;dh&amp;#39;).&lt;/li&gt;
&lt;li&gt;&amp;#39;:Gcommit&amp;#39;, &amp;#39;:Gblame&amp;#39; and &amp;#39;:Gmove&amp;#39; are other self-explanatory examples. Take a look at fugitive documentation for more details.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Viewing files difference&lt;/h3&gt;
&lt;p&gt;Open at least two windows with the text you want to see the differences and type &amp;#39;:diffthis&amp;#39; on each window.
For turning the diff off, type &amp;#39;:diffoff&amp;#39;. Use &amp;#39;dp&amp;#39; in one highlighted diff for putting it in the other window
or &amp;#39;do&amp;#39; to obtain the difference content from the other window.
Use &amp;#39;[c&amp;#39; and &amp;#39;]c&amp;#39; for navigating backwards and forwards to the next start of a change. See &amp;#39;:h diff&amp;#39; for more details.&lt;/p&gt;
&lt;h3&gt;Getting vim help&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;:h&amp;#39; or F1: open the Vim main help&lt;/li&gt;
&lt;li&gt;&amp;#39;:h command&amp;#39;: open the command help in a the help window&lt;/li&gt;
&lt;li&gt;Ctrl+]: open a link in the help&lt;/li&gt;
&lt;li&gt;Ctrl+T: go back to the prior help position&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Ruby specifics (Rspec, RDoc, etc)&lt;/h3&gt;
&lt;p&gt;Commands (won&amp;#39;t work in some terminals, use gVim or MacVim):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+s, r: get the RDoc for the word under cursor&lt;/li&gt;
&lt;li&gt;Ctrl+s, s: run rspec in the current opened spec&lt;/li&gt;
&lt;li&gt;Ctrl+s, x: alternate between spec and model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rails commands (use tab for auto-complete most commands):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;:Rview users/list.erb&amp;#39;: open the view&lt;/li&gt;
&lt;li&gt;&amp;#39;:Rcontroller users&amp;#39; and &amp;#39;:Rmodel user&amp;#39; are similar commands&lt;/li&gt;
&lt;li&gt;&amp;#39;gf&amp;#39;: when pressed over a line such as &amp;#39;render &amp;quot;users/list&amp;quot;&amp;#39; will open &amp;#39;users/list.erb&amp;#39; for instance.
When pressed over the &amp;#39;ApplicationController&amp;#39; word, it will take you to &amp;#39;application_controller.rb&amp;#39;.&lt;/li&gt;
&lt;li&gt;&amp;#39;:R&amp;#39;: Alternate between the controller action and the view when you follow the conventions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Debugging:&lt;/p&gt;
&lt;p&gt;You need to install the &amp;#39;ruby-debug-ide19&amp;#39; or &amp;#39;ruby-debug-ide&amp;#39; gem for this to work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;:Rdebugger bin/ruby_script&amp;#39; or &amp;#39;Rdebugger script/rails server&amp;#39; for a Rails application&lt;/li&gt;
&lt;li&gt;\db: alternate breakpoint&lt;/li&gt;
&lt;li&gt;\dn: step over&lt;/li&gt;
&lt;li&gt;\ds: step into&lt;/li&gt;
&lt;li&gt;\df: step out&lt;/li&gt;
&lt;li&gt;\dc: continue&lt;/li&gt;
&lt;li&gt;\dv: open variables window&lt;/li&gt;
&lt;li&gt;\dm: open breakpoints window&lt;/li&gt;
&lt;li&gt;\dt: open backtrace window&lt;/li&gt;
&lt;li&gt;\dd: remove all breakpoints&lt;/li&gt;
&lt;li&gt;&amp;#39;:RdbEval User.count&amp;#39; will evaluate &amp;#39;User.count&amp;#39;&lt;/li&gt;
&lt;li&gt;&amp;#39;:RdbCommand where&amp;#39; will send the &amp;#39;where&amp;#39; command to rdebug&lt;/li&gt;
&lt;li&gt;&amp;#39;:RdbCond user.admin?&amp;#39; will set the condition &amp;#39;user.admin?&amp;#39; to the breakpoint&lt;/li&gt;
&lt;li&gt;&amp;#39;:RdbCatch Errno::ENOENT&amp;#39; will catch the file not found exception, jumping to the file line of the exception,
allowing you to investigate the stack-trace, variables, etc.&lt;/li&gt;
&lt;li&gt;&amp;#39;:RdbStop&amp;#39; stops the debugger&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Refactoring&lt;/h3&gt;
&lt;p&gt;Although Vim doesn&amp;#39;t allow you to directly refactor some variable for instance (at least, I don&amp;#39;t know how to do that in Vim),
it can help you refactoring your code in many ways, from substitution commands to variable extraction like the example above:&lt;/p&gt;
&lt;p&gt;Suppose you want to refactor the code below as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;  if User.find(params[:id]) and current_user.admin?
  # ...
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;  @user = User.find(params[:id])
  raise NotFoundException unless @user and current_user.admin?
  # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For extracting the &amp;quot;User.find(params[:id])&amp;quot; to the &amp;quot;@user&amp;quot; variable, you can position the cursor under the &amp;quot;U&amp;quot; and run the
commands &amp;quot;c% @user&amp;quot; (change the content &amp;quot;User.find(params[:id])&amp;quot; with &amp;quot;@user&amp;quot;), &amp;quot;Ctrl+o, O&amp;quot; (execute the &amp;#39;O&amp;#39; command while
on insert mode [Ctrl+o] - create a new line above the current), &amp;quot;@user = &amp;quot; (just typing), &amp;#39;Ctrl+R &amp;quot;&amp;#39; (paste the cut content).&lt;/p&gt;
&lt;p&gt;With all these explanations, it may seem hard, but take a look at how we can achieve this with so few keystrokes: 
&lt;span style=&quot;background: yellow&quot;&gt;c% @user &amp;lt;Ctrl+O&amp;gt;O @user = &amp;lt;Ctrl+R&amp;gt;&amp;quot;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Learning how to use Vim in its full power will allow you to do many tasks quicker than any other editor or IDE in the overall.
For instance, RubyMine will allow you to do the same with less keystrokes for this specific case, but for special cases, Vim
will still be more useful and not much less productive than RubyMine for this common case. Actually, cutting &amp;quot;User.find(params[:id])&amp;quot;
is much faster in Vim (&amp;quot;c%&amp;quot;) than selecting the whole text in RubyMine or any other IDE. The same apply for change the content inside
quotes, parenthesis, XML tags, etc among other features.&lt;/p&gt;
&lt;h2&gt;What doesn&amp;#39;t work?&lt;/h2&gt;
&lt;p&gt;Unfortunately, I couldn&amp;#39;t find every feature I wanted in Vim yet. Some of them present on regular IDEs include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Except from Ruby, integrated debugging is probably missing for most languages&lt;/li&gt;
&lt;li&gt;Recent tab navigation using Ctrl+Tab like usually work in most IDEs&lt;/li&gt;
&lt;li&gt;Seamless integration with the system clipboard, unless using vim in &amp;#39;easy&amp;#39; mode with &amp;#39;evim&amp;#39; or &amp;#39;vim -y&amp;#39; commands&lt;/li&gt;
&lt;li&gt;For Java development, traditional IDEs like Netbeans, Eclipse or IntelliJ are more competent with auto-completion and
other language features&lt;/li&gt;
&lt;li&gt;Jumping to a tag in an existent tab, or open in a new one (currently I could just open in a new one). Maybe we should get used to work with buffers instead of tabs in Vim&lt;/li&gt;
&lt;li&gt;Integration with the Rails i18n infrastructure with the default backend. Rubymine has a great integration and a friend of mine has also developed something similar as a Netbeans
&lt;a href=&quot;http://luiszandonadi.heroku.com/en/articles/netbeans/2010-07-11-i18n-rails-with-netbeans&quot;&gt;plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;More to come&lt;/h2&gt;
&lt;p&gt;There are still more useful commands like folding and other interesting features that I&amp;#39;ll comment when I have more time available.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve already commented about several commands and I suggest you to start learning those that you use more often, like snippets,
simple search and replace, quick file opening, tabs usage and buffer navigation. For those that work with HTML, I would recommend
taking a look at the &amp;quot;surround&amp;quot; plug-in, that are specially useful for working with XML/HTML tags.&lt;/p&gt;
&lt;p&gt;As a last keynote, this article was written with Vim in the Markdown format. Many of these examples include tags and for escaping
them in the document, I&amp;#39;ve used the command &amp;#39;:%HTMLSpecialChars&amp;#39; from the plug-in &amp;#39;htmlspecialchars&amp;#39;.&lt;/p&gt;
&lt;p&gt;If you can take some time to improve your Vim skills it will save you many coding time during your coder life.&lt;/p&gt;
&lt;p&gt;Good advantage and have fun!&lt;/p&gt;
</content:encoded></item><item><title>Generating PDF with ODF templates in Rails</title><link>https://rosenfeld.page/articles/ruby-rails/2010_03_16_generating_pdf_with_odf_templates_in_rails/</link><guid isPermaLink="true">https://rosenfeld.page/articles/ruby-rails/2010_03_16_generating_pdf_with_odf_templates_in_rails/</guid><pubDate>Tue, 16 Mar 2010 21:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In 2009, I wrote an article for the &lt;a href=&quot;http://railsmagazine.com&quot;&gt;Rails Magazine&lt;/a&gt; Issue #4 - The Future of Rails - where
I presented an alternative to PDF generation from ODF templates, which can be generated using a regular text processor
such as OpenOffice.org or Microsoft Office (after converting the document to ODF).&lt;/p&gt;
&lt;p&gt;You can read the entire article &lt;a href=&quot;http://railsmagazine.com/issues/4&quot;&gt;downloading this magazine for free&lt;/a&gt; or
&lt;a href=&quot;http://magcloud.com/browse/issue/32751&quot;&gt;purchasing&lt;/a&gt; it. The application code illustrating this approach was published
by the magazine on &lt;a href=&quot;http://github.com/railsmagazine/rmag_downloads/tree/master/issue_4/rodrigo_rosas_genpdf/&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, I can&amp;#39;t host a working system providing a live demonstration due to my &lt;a href=&quot;http://heroku.com&quot;&gt;Heroku&lt;/a&gt; account
limitations, but it should be easy to follow the instructions in the article on your development or production environment.&lt;/p&gt;
&lt;p&gt;Do not hesitate in sending me any questions, through comments on this site or by e-mail, if you prefer.&lt;/p&gt;
</content:encoded></item><item><title>Site&apos;s Debut</title><link>https://rosenfeld.page/articles/2010_03_16_site_debut/</link><guid isPermaLink="true">https://rosenfeld.page/articles/2010_03_16_site_debut/</guid><pubDate>Tue, 16 Mar 2010 20:40:00 GMT</pubDate><content:encoded>&lt;p&gt;For my first article, I chose to write about the reasons that resulted in my decision to finally develop my site, as
well as talking about its technical structure and why I have taken such approach.&lt;/p&gt;
&lt;h2&gt;Motivation&lt;/h2&gt;
&lt;p&gt;I have been considering writing my site for a long while. There were lots of subjects I had interest in writing about,
but for several years I really had no free time to do it. There were tons of distractions I had to deal with: graduation,
writing my master thesis, looking for jobs, working, marriage, more working. When I had some time at night, I was
really exhausted.&lt;/p&gt;
&lt;p&gt;During this time, I considered using some ready to deploy system, such as &lt;a href=&quot;http://www.blogger.com/&quot;&gt;Blogger&lt;/a&gt;,
&lt;a href=&quot;http://wordpress.org/&quot;&gt;Wordpress&lt;/a&gt; and others, but I didn&amp;#39;t like the idea of loosing control over by articles. Although
customizing Wordpress was an option, it is written in PHP, so, in short: no, thanks. I wanted my site to be exactly as
I desired and these tools wouldn&amp;#39;t allow me total flexibility over it and I guessed it would be too hard to migrate all
my articles to a new system later if I decided to.&lt;/p&gt;
&lt;p&gt;When I found some available time at night, I came to think in building my own site, in my way, with
&lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt;. But I always faced the same problem. I wasn&amp;#39;t inclined to invest money regularly on
some hosting provider when I didn&amp;#39;t intended any payback from my site. I never found a free hosting service either that
supported Rails and neither was willing to develop my site with other framework.&lt;/p&gt;
&lt;p&gt;Recently, lots of blogs that I follow commented about &lt;a href=&quot;http://cloudhead.io/toto&quot;&gt;Toto&lt;/a&gt;. So many of them that I decided
to get a deeper understanding of it and doing some tests. Toto is a blog system written in about 300 lines of Ruby code,
in top of &lt;a href=&quot;http://rack.rubyforge.org/&quot;&gt;Rack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Toto was the reason that made me decide to finally write my site. These were the main ideas that inspired this site
design:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The articles get stored on disk, instead of a database. This allows easy version management of the articles, using
my favorite version control system: &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Comments are managed by &lt;a href=&quot;http://disqus.com&quot;&gt;Disqus&lt;/a&gt;, a system I had never heard of before and that is just fantastic!&lt;/li&gt;
&lt;li&gt;Finally, the main reason was that Toto increased my interest in &lt;a href=&quot;http://heroku.com/&quot;&gt;Heroku&lt;/a&gt;. I had already read
about it before, but every time I tried to understand what was it about, I didn&amp;#39;t get the idea instantly and, with
little time to read all my feeds, I ended up not being interested enough for digging deeper. After reading more about
Toto, I understood that Heroku was a service that would allow me to host a Ruby web application with no cost. My
sincerely thanks to Toto and Heroku who made this site possible!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Why not Toto?&lt;/h2&gt;
&lt;p&gt;My first attempt was doing exactly Toto&amp;#39;s recommended procedure. As long as I developed my site with Toto, I faced some
obstacles:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first one was related to code highlighting. This one was easy to solve after following some instructions found
in some blogs, explaining how to embed &lt;a href=&quot;http://coderay.rubychan.de/&quot;&gt;CodeRay&lt;/a&gt; in Toto, for instance.&lt;/li&gt;
&lt;li&gt;The next challenge was about internationalization. I wanted to write articles both in English and Portuguese. I
wanted some support for internationalization and Toto didn&amp;#39;t worry about this, as it was designed to be minimalistic.
I don&amp;#39;t blame it, but this was a concern while writing deciding or not to use Toto.&lt;/li&gt;
&lt;li&gt;Finally, I wanted to group my articles in directories for organizing the articles by topics such as
&lt;a href=&quot;http://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt;/Rails, general programming, operating systems, infrastructure, etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Fortunately, Toto is so compact and well written that it is a trivial task to adapt it in a full Rails application and
change it to meet my expectations. Rails has I18n native support, so I only needed to implement the topics organization.&lt;/p&gt;
&lt;p&gt;Basically, the main ideas implemented on this site were extracted from Toto. I&amp;#39;m very grateful to its creator
&lt;a href=&quot;http://cloudhead.net/cv/&quot;&gt;Alexis Sellier&lt;/a&gt; for the inspiration that resulted on this site.&lt;/p&gt;
&lt;p&gt;No databases are being used for now. Site statistics are handled by &lt;a href=&quot;http://www.google.com/analytics/&quot;&gt;Google Analytics&lt;/a&gt;.
The images used in this site are hosted at &lt;a href=&quot;http://aws.amazon.com/s3/&quot;&gt;Amazon S3&lt;/a&gt; and &lt;a href=&quot;http://ultraviolet.rubyforge.org/&quot;&gt;Ultraviolet&lt;/a&gt;
is the installed code highlighter. &lt;a href=&quot;http://github.com/rtomayko/rdiscount&quot;&gt;RDiscount&lt;/a&gt; was chosen for parsing
&lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Given the opening, I hope you enjoy the next articles.&lt;/p&gt;
</content:encoded></item></channel></rss>