Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce on_response blocks to set attributes on calculator #2408

Merged

Conversation

floehopper
Copy link
Contributor

Description

Supersedes #2405.

Trello card: https://trello.com/c/V6nqIWcJ

The idea is that we'll use these on_response blocks in a question block to set attributes on the calculator/policy object instead of doing that in next_node blocks which is the current "new-style" approach.

I've updated the following flows to use the new on_response blocks:

  • calculate-statutory-sick-pay
  • check-uk-visa
  • marriage-abroad
  • overseas-passports
  • part-year-profit-tax-credits

These are the only flows which use the new-style pattern of instantiating a calculator object in the first question, setting each response as an attribute on the calculator, and encapsulating all the policy logic in the calculator. I don't think it makes sense to apply the same approach to any of the other flows until they have been converted closer to the new-style.

Motivation

One advantage of doing this is to separate out the attribute-setting code which should make it easier to do automatically in future. Theoretically the next_node block will only need access to the calculator and not to the response.

Another advantage is that we can avoid having to pass the response into any validation-related methods on the calculator which should make them more ActiveModel-like.

The new on_response blocks are run before both next_node_calculation and validate blocks.

External changes

None. This is just a refactoring.

@floehopper
Copy link
Contributor Author

Since no comments have been added to the commits in this PR, I'm going to rebase it against master and force-push to fix the conflicts reported by GitHub above.

@floehopper floehopper force-pushed the introduce-on-response-blocks-to-set-attributes-on-calculator branch from f7f5093 to 4bde089 Compare March 30, 2016 17:17
@floehopper
Copy link
Contributor Author

Rebase & force-push done - GitHub is now showing no conflicts. This is ready for review.

@chrisroos chrisroos self-assigned this Apr 6, 2016
@chrisroos
Copy link
Contributor

Would you be able to update the commit note for 4a26b6c ("Make CalculateStatutorySickPayFlowTest more realistic") to explain why you've used a real instead instead of a stub?

@chrisroos
Copy link
Contributor

Fix Style/ClosingParenthesisIndentation Rubocop violations (7bf40ba)

Annoyingly I don't think these are real violations - I think they are caused by
a problem with the -diff option on govuk-lint-ruby. However, this seems to
fix the problem and I don't mind the style of the resulting code.

You might be able to change this back now that we've stopped using the --diff option of govuk-lint-ruby.

@chrisroos
Copy link
Contributor

This looks great to me, @floehopper. Good work!

@chrisroos chrisroos added the LGTM label Apr 6, 2016
@floehopper
Copy link
Contributor Author

Would you be able to update the commit note for 4a26b6c ("Make CalculateStatutorySickPayFlowTest more realistic") to explain why you've used a real instead instead of a stub?

I've added an empty squash-commit with some notes to remind me to improve the commit note: 21c04ee.

@floehopper floehopper force-pushed the introduce-on-response-blocks-to-set-attributes-on-calculator branch from cea2332 to dacb3c9 Compare April 11, 2016 16:54
@floehopper
Copy link
Contributor Author

You might be able to change this back now that we've stopped using the --diff option of govuk-lint-ruby.

I tried reverting that commit, but the violations still happened, so I think I'll leave it in place. I've added an empty squash-commit to remind me to update the commit note accordingly: dacb3c9.

@floehopper
Copy link
Contributor Author

I'm going to do an interactive rebase to incorporate the squash-commits, then rebase against master to resolve the conflicts reported by GitHub, before force-pushing (since there are no commit comments) in preparation for merging.

Note that this is just documenting the existing behaviour - it's not intended
as an endorsement of the existing behaviour.
This does pretty much everything that `SmartAnswer::Calculation` does, except
that it doesn't assign the result of the block to a specified state variable.
Hopefully you can see this by comparing the unit tests for the two classes.

I'm planning to use this to introduce a new type of block to the Flow/Question
DSL which will be called immediately after receiving the response from the
user. However, I've named the new class very generically, because there's no
reason it couldn't be used at other points in the DSL.

I did contemplate other slightly more specific names e.g.
`NonAssigningCalculation` and `BlockEvaluatableInContextOfState`.

For the former, I thought that the `Calculation` suffix was a bit confusing,
because I think it conveys the idea that it has a result.

I thought the latter was unwieldy and came to the conclusion that really this
is just a block - it's just enhanced with a method that allows it to be called
in the context of a `SmartAnswer::State`. And the method signature of the
`#evaluate` method is enough to explain the latter.

Thus I think naming it `SmartAnswer::Block` is the best option.
The idea is that we'll use these blocks to set attributes on the
calculator/policy object instead of doing that in `next_node` blocks.

One advantage of doing this is to separate out the attribute-setting code which
should make it easier to do automatically in future.

Another advantage is that we can avoid having to pass the response into any
validation-related methods on the calculator which should make them more
ActiveModel-like.

The new `on_response` blocks are run *before* both `next_node_calculation` and
`validate` blocks.

The existing unit tests around this area of the codebase leave a bit to be
desired, but I've added new tests as best I can roughly following existing
patterns. I did also contemplate adding an `EngineIntegrationTest` with a
new fixture flow, but I decided that it would be overkill and added the test to
`FlowTest` instead. I feel as if this gives sufficient test coverage for the
new functionality.
Use a real instance of the calculator instead of a stub:

* Using a real object rather than a stub means that we'll see an error if we
  stub a non-existent method.
* We can re-use the calculator instance created in the top-level setup.
* Stubbing simple accessor methods seems like overkill.
I think these are remnants from when we weren't stubbing the validation
methods on the calculator.
It seems better to separate the setting of attributes on the calculator from
the routing logic in `next_node` blocks. The recently introduced `on_response`
block allows us to do this. It also means the response will be available on the
calculator as an attribute when validation methods are called which means we
won't need to pass the response into these methods, thus simplifying the code.

Note that I've had to set the `calculator` state variable in the first
`on_response` block, because these blocks are executed before
`next_node_calculation` blocks.
Now that the responses are available as attributes we don't need to pass the
response into the validation methods. This makes the validations closer to the
ActiveModel style.

I've had to use a slight bodge in `#valid_last_payday_before_offset?`. I've
added 1 day to the RHS to counteract the fact that the validation was previously
done on the raw response rather than `relevant_period_from` which is the raw
response plus 1 day. I'm planning to improve this later as part of this Trello
card [1].

[1]: https://trello.com/c/uu0HeZee
It seems better to separate the setting of attributes on the calculator from
the routing logic in `next_node` blocks. The recently introduced `on_response`
block allows us to do this. It also means the response will be available on the
calculator as an attribute when validation methods are called which means we
won't need to pass the response into these methods, thus simplifying the code.

Note that I've had to set the `calculator` state variable in the first
`on_response` block, because these blocks are executed before
`next_node_calculation` blocks.
Now that the responses are available as attributes we don't need to pass the
response into the validation methods. This makes the validations closer to the
ActiveModel style.
It seems better to separate the setting of attributes on the calculator from
the routing logic in `next_node` blocks. The recently introduced `on_response`
block allows us to do this.

Note that I've had to set the `calculator` state variable in the first
`on_response` block, because these blocks are executed before
`next_node_calculation` blocks.
It seems better to separate the setting of attributes on the calculator from
the routing logic in `next_node` blocks. The recently introduced `on_response`
block allows us to do this.

Note that I've had to set the `calculator` state variable in the first
`on_response` block, because these blocks are executed before
`next_node_calculation` blocks.
It seems better to separate the setting of attributes on the calculator from
the routing logic in `next_node` blocks. The recently introduced `on_response`
block allows us to do this. It also means the response will be available on the
calculator as an attribute when validation methods are called which means we
won't need to pass the response into these methods, thus simplifying the code.

Note that I've had to set the `calculator` state variable in the first
`on_response` block, because these blocks are executed before
`next_node_calculation` blocks.
Now that the responses are available as attributes we don't need to pass the
response into the validation methods. This makes the validations closer to the
ActiveModel style.

Note that I've extracted a new `valid_current_location?` method on the
`OverseasPassportsCalculator` to better match the style we've used elsewhere.
@floehopper floehopper force-pushed the introduce-on-response-blocks-to-set-attributes-on-calculator branch from dacb3c9 to a93ae65 Compare April 11, 2016 17:11
@floehopper floehopper merged commit f23ab9c into master Apr 11, 2016
@floehopper floehopper deleted the introduce-on-response-blocks-to-set-attributes-on-calculator branch April 11, 2016 17:17
floehopper added a commit that referenced this pull request Jun 30, 2016
In #2408 we introduced `on_response` blocks with the idea of using them to build
and store a calculator object in a `calculator` state variable, and to manually
store the response to each question on the calculator. This is instead of using
`save_input_as` which stores the response as a state variable.
floehopper added a commit that referenced this pull request Jun 30, 2016
In #2408 we introduced `on_response` blocks with the idea of using them to build
and store a calculator object in a `calculator` state variable, and to manually
store the response to each question on the calculator. This is instead of using
`save_input_as` which stores the response as a state variable.

This commit updates the documentation to reflect the new state of affairs.
floehopper added a commit that referenced this pull request Jul 5, 2016
In #2408 we introduced `on_response` blocks with the idea of using them to build
and store a calculator object in a `calculator` state variable, and to manually
store the response to each question on the calculator. This is instead of using
`save_input_as` which stores the response as a state variable.

This commit updates the documentation to reflect the new state of affairs.
floehopper added a commit that referenced this pull request Jul 6, 2016
In #2408 we introduced `on_response` blocks with the idea of using them to build
and store a calculator object in a `calculator` state variable, and to manually
store the response to each question on the calculator. This is instead of using
`save_input_as` which stores the response as a state variable.
floehopper added a commit that referenced this pull request Jul 6, 2016
In #2408 we introduced `on_response` blocks with the idea of using them to build
and store a calculator object in a `calculator` state variable, and to manually
store the response to each question on the calculator. This is instead of using
`save_input_as` which stores the response as a state variable.

This commit updates the documentation to reflect the new state of affairs.
floehopper added a commit that referenced this pull request Jul 6, 2016
In #2408 we introduced `on_response` blocks with the idea of using them to build
and store a calculator object in a `calculator` state variable, and to manually
store the response to each question on the calculator. This is instead of using
`save_input_as` which stores the response as a state variable.

This commit updates the documentation to reflect the new state of affairs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants