Writing Architecture Documents (for developers)

Tute Costa

Our colleague Martin was about to start working on a small-scale feature, an addition to a module that wasn’t open for extension and couldn’t easily support it.

He could shoehorn his use case on top of existing architecture without affecting others much or lay a more robust foundation over which he’d implement his use case. This could also help fix long-standing bugs and enable the implementation of new features that we foresee in our next two years (but would be hard to add now). In other words, “make the change easy, then make the easy change”.

Mystery Guest Development Edition

Sebastian Armano

Mystery Guest is the name of an anti-pattern that often appear in tests. In short, it is caused by non explicitly declaring or naming a value, which is tested over that faulty declaration. The issue is not apparent at first, as the test is created at the same time as the fixture or factory that supports it. Eventually, when a change is needed in that support object to test something else, the change unintentionally breaks the first test.

For a test which verifies that the full_name of a user is the combination of first_name and last_name, those two properties need to appear explicitly on the test setup. Even if you have user factory, you are not testing the factory, but your own user with first_name and last_name. If the users in your application also need, say, an address not being tested in this example, the factory can provide that.

So the question arises: are tests the only ones affected by this anti-pattern?

A git branching model for 15 people sharing a single testing environment

Tute Costa

My development team collaborates every day with a QA team to ship timely well-tested work. We work on a feature and put it up for testing; if QA passes it, we prepare it for production. Every week, after QAs perform full regression testing, we deploy to production (occasionally, they spot tricky bugs or regressions that we fix or revert).

A typical workflow, but with a caveat: we share a single testing environment (and thus git branch), which complicates preparing releases: either the shared branch contains untested code, or developers wait on QA and on each other to merge after acceptance. We tried for long to solve this from scratch by provisioning more testing environments, so that developers and QA work in parallel while the shared branch only contains tested work, but in vain: we depend on a third party that so far can’t provision extra testing environments (an Electronic Health Record –EHR– company).

How does this team of 12 developers and 3 QAs get their work tested on the one shared environment, deploy only acceptance-tested work weekly, without code freezes?

Rails Monolith towards Engines spike - Our story

Tute Costa

This year my team started working on a new UI for our patient check-in application, with slightly modified rules for specific use cases and forms. It would reuse most of our backend software with few changes. We named it Bariloche.

Bariloche is a new UI for our patient check-in workflows, targeted for Urgent Care facilities. Given that the UI would start from scratch, we’d use it as a testbed to build our frontend entirely with React Components. Everything would be namespaced under the “Bariloche” name.

Such a clear boundary between the monolith and this product made it an ideal case to try an Engine implementation. Given Bariloche would share the data layer declared by the main app and not need database migrations, our first step towards Engines would be smaller than for other potential extractions we could foresee.

Backward-compatible database migrations

Tute Costa

My team has a policy of not applying destructive changes to our database. We don’t, for example, remove a column or table when deprecated, and we don’t rename either, as renaming is akin to removing a name the code uses.

Our deployment process performs database changes about a minute before the related code changes go live. During this time, Rails might run database queries using an out-of-date schema, erroring out. As the usage of our app continues to increase, even sub-second rename migrations bring down several in-flight requests.

Avoiding nil in Ruby programs (and NULL in databases)

Tute Costa

Most Ruby developers see the following exception in production, no matter how well taken care their codebase is:

1
NoMethodError: undefined method `name' for nil:NilClass

And the search begins. Was it a user? Or another object that would respond to #name if present? Was it a typo? Many different statements can return nil:

Development/Production parity for Rails Internationalization

Mauro Otonelli

To support both English and Spanish in web apps, we can use Ruby’s I18n library, which allows for easy translations through YAML files for each language. If a translation is missing, ideally we’d like to see an error in our tests, which makes the test suite fail. However, if our development environment is not set up to raise exceptions, there could be bugs lurking, or waiting to be introduced.

One such instance happened to us recently, because our I18n.backend (yes, that’s a thing!) in Rails was different in the development/testing and production environments. Development used the “base” i18n backend, while production was set up to use the “fallbacks” backend.

Keep It Simple (KISS coding principle)

Tute Costa

The app we maintain has a set of steps (currently two) a user may have to fill before moving on. One step is always shown, while the other can be disabled with a feature flag. We assume this list may grow, and even when it doesn’t, we know code is copied over to other parts of the codebase, so we better get it right early.

Our first implementation:

1
2
3
4
5
6
def supported_steps
  {
    current_medications: true,
    allergies_review: Feature.enabled?(PREVISIT_ALLERGIES),
  }.select { |_step_name, enabled| enabled }.keys
end

A suggestion during code review:

1
2
3
4
5
def supported_steps
  steps = [:current_medications]
  steps << :allergies_review if Feature.enabled?(PREVISIT_ALLERGIES)
  steps
end

It’s quicker to get what’s happening in the second option, and while the methods stay short, they are practically equal. Our code reviews can get lengthy so we try not to chime in when either option is fine, but I suggested the first as a simpler option (even if not easier)[1]. Let’s see why.

Using logs to power up your Rails development workflow

Mauro Otonelli

When working on Rails applications, I find tailing the development log and watching it as I navigate through pages very useful. Some of the questions that should be in the back of your mind while looking at it are:

  • Am I hitting the right URL, with the proper HTTP method?
  • Am I sending the right parameters? (Are they all necessary?)
  • Are there any warnings/exceptions that I should handle?
  • Does the ORM generate the right SQL statements?
  • Is my request taking a longer time than expected?
  • Am I making unnecessary 3rd party API requests?

Reporting from ephemeral containers in production

Sebastian Armano

Reporting is not a particular task of business analysts anymore. Anyone at any department, at any point in time, needs a quick report based on the latest data to validate their decisions. Having the ability to create small custom reports in a couple of minutes, and in a format that can be consumed by any analysis software is a powerful resource to have in our belt.

Page 1 of 2 Next ↠