From 482d9f3ab3115eb4e6b52aa5cf82cc8f3d10cae2 Mon Sep 17 00:00:00 2001 From: Kevin Dew Date: Fri, 5 Jun 2020 20:47:06 +0100 Subject: [PATCH] Break up Rails conventions with headers Following feedback that this doc was somewhat hard to follow I've tried to break this up into a number of sections to group together similar concerns. The most notable change this causes to the doc is that the testing tooling and testing strategy are in separate sections. --- ...conventions-for-rails-applications.html.md | 202 +++++++++--------- 1 file changed, 104 insertions(+), 98 deletions(-) diff --git a/source/manual/conventions-for-rails-applications.html.md b/source/manual/conventions-for-rails-applications.html.md index 5ae67872a7..52bfca2a21 100644 --- a/source/manual/conventions-for-rails-applications.html.md +++ b/source/manual/conventions-for-rails-applications.html.md @@ -27,7 +27,7 @@ conventions in an adopted framework. [Ruby on Rails]: https://rubyonrails.org/ [consistent-govuk]: https://docs.google.com/document/d/1jEjPOFJ2s1cjQv9vHAbE-KF68LSletpnUVaG5lXlHy4/edit#heading=h.yod40rauhyhu -## Follow industry conventions +## Our approach GOV.UK's use of Rails is intended to be consistent with the conventions of the framework itself and we intend to embrace developments and deprecations @@ -35,10 +35,9 @@ from the framework. Where GOV.UK apps differ from Rails conventions (such as using the RSpec testing framework) these are intended to be consistent with common industry practices. -GOV.UK Rails applications aim to follow -[12 factor](https://12factor.net/) conventions. +## Tooling choices -## Use GOV.UK supporting Gems +### Use GOV.UK supporting Gems GOV.UK have published a number of gems that help achieve common needs across Ruby / Rails applications: @@ -90,7 +89,7 @@ introduced by these gems. [slimmer]: https://github.com/alphagov/slimmer [issue-example]: https://github.com/alphagov/govuk_app_config/issues/121 -## Data storage +### Data storage For non-specialist database needs you should use [PostgreSQL](https://www.postgresql.org/) with [ActiveRecord][]. The @@ -115,7 +114,7 @@ used. [Amazon S3]: https://aws.amazon.com/s3/ [ActiveStorage]: https://guides.rubyonrails.org/active_storage_overview.html -## Background job processing +### Background job processing The preferred approach for background job processing is to use [ActiveJob][] with [Sidekiq][] with the [govuk_sidekiq][] gem providing configuration. @@ -130,7 +129,7 @@ where [sidekiq-scheduler][] is the conventional choice to achieve this. [ActionMailer]: https://guides.rubyonrails.org/action_mailer_basics.html [sidekiq-scheduler]: https://github.com/moove-it/sidekiq-scheduler -## JavaScript package management +### JavaScript package management For Rails applications you should use the [Yarn](https://yarnpkg.com) package manager for JavaScript packages. Yarn is preferable to using @@ -139,7 +138,7 @@ with Yarn, providing default tasks and automating some workflows. [yarn-integration]: https://guides.rubyonrails.org/5_1_release_notes.html#yarn-support -## Frontend assets +### Frontend assets GOV.UK applications use the Rails [asset pipeline][] for building assets. We aspire to migrate to [webpacker][] as the conventional approach when we have @@ -149,7 +148,7 @@ resolved [blocking issues][]. [webpacker]: https://github.com/rails/webpacker [blocking issues]: https://github.com/alphagov/govuk_publishing_components/issues/505 -## Sending emails +### Sending emails [GOV.UK Notify][] is the preferred approach for sending email. The [mail-notify][] gem is conventionally used to integrate Notify with @@ -160,12 +159,105 @@ GOV.UK applications use Notify. [mail-notify]: https://github.com/dxw/mail-notify [govuk-notify-docs]: /manual/govuk-notify.html -## Configure Rails as `api_only` for API projects +### Testing utilities + +The preferred framework for testing Rails applications is [rspec-rails][] where +we aim to adhere to the projects conventions. [rubocop-govuk][] provides +a linting configuration for RSpec. For mocking and test doubles you should use +the provided [rspec-mocks][] framework. + +When working with rspec-rails we prefer merging the [spec_helper.rb][] and +[rails_helper.rb][] files into a [single spec_helper.rb][] to avoid the +complexities of two configuration files. We also choose to specify +[`--require spec_helper`][rspec-file-example] in a [`.rspec` file][rspec-file] +to avoid prefixing every test with `require "spec_helper"`. + +Common tools used with RSpec are: + +- [webmock][] gem to stub HTTP requests, for stubbing communication between + GOV.UK applications [gds-api-adapters][] provides a library of helper methods + that are preferred to manual stubbing; +- [SimpleCov][] for monitoring code coverage; +- [factory_bot_rails][] for providing fixtures/test data; +- [Climate Control][] gem for modifying environment variables within tests; +- [`ActiveSupport::Testing::TimeHelpers`][time-helpers] for time manipulation. + +The conventional testing framework for JavaScript files in GOV.UK Rails +applications is [jasmine][]. This is dictated by jasmine integrating +with the [asset-pipeline][] which rules out other common JavaScript testing +frameworks such as Jest or Karma. [Jasmine should be configured to run tests +with Chrome headless][jasmine-chrome] as opposed to the default PhantomJS +(which is a project no longer under development). + +[rspec-rails]: https://relishapp.com/rspec/rspec-rails/docs +[rspec-mocks]: https://relishapp.com/rspec/rspec-mocks/docs +[spec_helper.rb]: https://github.com/rspec/rspec-core/blob/7b6b9c3f2e2878213f97d6fc9e9eb23c323cfe1c/lib/rspec/core/project_initializer/spec/spec_helper.rb +[rails_helper.rb]: https://github.com/rspec/rspec-rails/blob/a9e3f18c47cf83e0a40c3870f3bab5fe2f4e609a/lib/generators/rspec/install/templates/spec/rails_helper.rb +[single spec_helper.rb]: https://github.com/alphagov/content-publisher/blob/92eb7afe4344d32905b30204c94e033332342e6b/spec/spec_helper.rb +[rspec-file-example]: https://github.com/alphagov/content-publisher/blob/92eb7afe4344d32905b30204c94e033332342e6b/.rspec +[rspec-file]: https://github.com/rspec/rspec/wiki#rspec +[webmock]: https://github.com/bblimke/webmock +[webmock-localhost]: https://github.com/alphagov/content-publisher/blob/8c88972d461c8c25ae4e8c8b22c367eb28d6b79a/spec/spec_helper.rb#L18 +[simplecov]: https://github.com/colszowka/simplecov +[factory_bot_rails]: https://github.com/thoughtbot/factory_bot_rails +[factory-bot-lint]: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#linting-factories +[Climate Control]: https://github.com/thoughtbot/climate_control +[time-helpers]: https://api.rubyonrails.org/v6.0.2/classes/ActiveSupport/Testing/TimeHelpers.html +[jasmine]: https://github.com/jasmine/jasmine-gem +[asset-pipeline]: #frontend-assets +[jasmine-chrome]: https://github.com/alphagov/content-publisher/blob/f26d9b551842fdf2084159b5b7f1bb078da56936/spec/javascripts/support/jasmine_helper.rb +## Configuration + +### Embrace 12 factor conventions + +GOV.UK Rails applications aim to follow +[12 factor](https://12factor.net/) conventions. These should manifest in your +Rails application with practices such as: + +- environmental configuration done by environment variables, for example using + `ENV["DATABASE_URL"]` over hardcoding the production database configuration; +- close parity between development and production environments, for example using + PostgreSQL in all environments - as opposed to SQLite for development and + PostgreSQL for production; +- avoiding, where possible, the need for additional configuration on the + serving machine, for example needing additional Nginx rules to serve requests. + +### Use `api_only` mode for API projects For applications that do not serve requests to a web browser you should -configure the Rails application to be [API only][]. +configure the Rails application to be [API only][], this simplifies Rails by +removing unnecessary functionality. If you need to add a web browser interface +to an API application you should consider creating a distinct frontend +application (for example: [email-alert-frontend][] and [email-alert-api][]). [API only]: https://guides.rubyonrails.org/api_app.html +[email-alert-frontend]: https://github.com/alphagov/email-alert-frontend +[email-alert-api]: https://github.com/alphagov/email-alert-api + +### Editing of microcopy by non-developers + +When it is intended for non-developers to edit microcopy in an application it is +conventional to use [Rails Internationalization (I18n)][i18n] to abstract +the copy outside of the application code. We use this even when an application +is only in English. These files are stored in `/config/locales` as per Rails +convention. You should only use these files for accessing copy and not +for any application configuration. + +[i18n]: https://guides.rubyonrails.org/i18n.html + +### Error handling + +GOV.UK Rails applications should anticipate failure and do so gracefully. This +[happens automatically, to a degree, on GOV.UK frontend +applications][frontend-errors] but not on admin applications where there is more +granular control over error responses. GOV.UK Rails applications should be +configured to provide GOV.UK branded error responses. +[Content Publisher][cp-errors] provides an example of implementing this with +the [GOV.UK admin layout][]. + +[frontend-errors]: /manual/errors.html +[cp-errors]: https://github.com/alphagov/content-publisher/pull/1252 +[GOV.UK admin layout]: https://components.publishing.service.gov.uk/component-guide/layout_for_admin ## Organising your code @@ -209,31 +301,6 @@ to use [architectural decision records][adr] in the `/docs/adr` directory [adr]: http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions [adr-example]: https://github.com/alphagov/content-publisher/blob/master/docs/adr/0002-use-local-datastore.md -## Editing of microcopy by non-developers - -When it is intended for non-developers to edit microcopy in an application it is -conventional to use [Rails Internationalization (I18n)][i18n] to abstract -the copy outside of the application code. We use this even when an application -is only in English. These files are stored in `/config/locales` as per Rails -convention. You should only use these files for accessing copy and not -for any application configuration. - -[i18n]: https://guides.rubyonrails.org/i18n.html - -## Error handling - -GOV.UK Rails applications should anticipate failure and do so gracefully. This -[happens automatically, to a degree, on GOV.UK frontend -applications][frontend-errors] but not on admin applications where there is more -granular control over error responses. GOV.UK Rails applications should be -configured to provide GOV.UK branded error responses. -[Content Publisher][cp-errors] provides an example of implementing this with -the [GOV.UK admin layout][]. - -[frontend-errors]: /manual/errors.html -[cp-errors]: https://github.com/alphagov/content-publisher/pull/1252 -[GOV.UK admin layout]: https://components.publishing.service.gov.uk/component-guide/layout_for_admin - ## Testing strategies We aim for well tested Rails applications that provide a good degree of coverage @@ -241,40 +308,7 @@ and provide assurances that an application is operating correctly. We value test suites that are fast to run, easy to read and [test things consistently at different abstractions (unit, integration and functional)][cp-testing-strategy]. -### Common tooling - -The preferred framework for testing Rails applications is [rspec-rails][] where -we aim to adhere to the projects conventions. [rubocop-govuk][] provides -a linting configuration for RSpec. For mocking and test doubles you should use -the provided [rspec-mocks][] framework. - -When working with rspec-rails we prefer: - -- Merging the [spec_helper.rb][] and [rails_helper.rb][] files into a - [single spec_helper.rb][] to avoid the complexities of two configuration - files. -- Specifying [`--require spec_helper`][rspec-file-example] in a - [`.rspec` file][rspec-file] to avoid prefixing every test with - `require "spec_helper"`. - -The conventional choice for stubbing HTTP requests is the [webmock][] gem, -which should be configured webmock to disable [real requests outside of -localhost][webmock-localhost]. For stubbing communication between GOV.UK -applications [gds-api-adapters][] provides a library of helper methods that -are preferred to manual stubbing. - -For monitoring code coverage we typically use the [SimpleCov] gem. - -For fixtures we conventionally use [factory_bot_rails][] and it is recommended -that you [lint your factories][factory-bot-lint] as part of an applications -CI process. - -When utilising environment variables in tests it is recommended to use -the [Climate Control][] gem which offers a simple consistent approach. - -For time manipulation in tests Rails has built in helpers in -[`ActiveSupport::Testing::TimeHelpers`][time-helpers], it is preferable to use -these rather than an install an additional gem such as Timecop. +[cp-testing-strategy]: https://github.com/alphagov/content-publisher/blob/f26d9b551842fdf2084159b5b7f1bb078da56936/docs/testing-strategy.md ### Feature/system testing @@ -304,31 +338,3 @@ approach][rspec-request-moj] to replace [controller specs][] reflecting the [rspec-request-moj]: https://medium.com/just-tech/rspec-controller-or-request-specs-d93ef563ef11 [controller specs]: https://relishapp.com/rspec/rspec-rails/docs/controller-specs [controller-rails-5]: https://github.com/rails/rails/issues/18950 - -### Javascript - -The conventional testing framework for JavaScript files in GOV.UK Rails -applications is [jasmine][]. This is dictated by jasmine integrating -with the [asset-pipeline][] which rules out other common JavaScript testing -frameworks such as Jest or Karma. [Jasmine should be configured to run tests -with Chrome headless][jasmine-chrome] as opposed to the default PhantomJS -(which is a project no longer under development). - -[cp-testing-strategy]: https://github.com/alphagov/content-publisher/blob/f26d9b551842fdf2084159b5b7f1bb078da56936/docs/testing-strategy.md -[rspec-rails]: https://relishapp.com/rspec/rspec-rails/docs -[rspec-mocks]: https://relishapp.com/rspec/rspec-mocks/docs -[spec_helper.rb]: https://github.com/rspec/rspec-core/blob/7b6b9c3f2e2878213f97d6fc9e9eb23c323cfe1c/lib/rspec/core/project_initializer/spec/spec_helper.rb -[rails_helper.rb]: https://github.com/rspec/rspec-rails/blob/a9e3f18c47cf83e0a40c3870f3bab5fe2f4e609a/lib/generators/rspec/install/templates/spec/rails_helper.rb -[single spec_helper.rb]: https://github.com/alphagov/content-publisher/blob/92eb7afe4344d32905b30204c94e033332342e6b/spec/spec_helper.rb -[rspec-file-example]: https://github.com/alphagov/content-publisher/blob/92eb7afe4344d32905b30204c94e033332342e6b/.rspec -[rspec-file]: https://github.com/rspec/rspec/wiki#rspec -[webmock]: https://github.com/bblimke/webmock -[webmock-localhost]: https://github.com/alphagov/content-publisher/blob/8c88972d461c8c25ae4e8c8b22c367eb28d6b79a/spec/spec_helper.rb#L18 -[simplecov]: https://github.com/colszowka/simplecov -[factory_bot_rails]: https://github.com/thoughtbot/factory_bot_rails -[factory-bot-lint]: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#linting-factories -[Climate Control]: https://github.com/thoughtbot/climate_control -[time-helpers]: https://api.rubyonrails.org/v6.0.2/classes/ActiveSupport/Testing/TimeHelpers.html -[jasmine]: https://github.com/jasmine/jasmine-gem -[asset-pipeline]: #frontend-assets -[jasmine-chrome]: https://github.com/alphagov/content-publisher/blob/f26d9b551842fdf2084159b5b7f1bb078da56936/spec/javascripts/support/jasmine_helper.rb