Skip to content

LG-12159: Refactor selfie_success to selfie_status and make it return a symbol#9953

Merged
eileen-nava merged 21 commits intomainfrom
em/12159-refactor-selfie-success
Jan 24, 2024
Merged

LG-12159: Refactor selfie_success to selfie_status and make it return a symbol#9953
eileen-nava merged 21 commits intomainfrom
em/12159-refactor-selfie-success

Conversation

@eileen-nava
Copy link
Contributor

🎫 Ticket

LG-12159: Change selfie_success to return a symbol

🛠 Summary of changes

@eileen-nava eileen-nava requested review from a team, charleyf and zachmargolis and removed request for a team January 22, 2024 19:22
@eileen-nava eileen-nava changed the title Em/12159 refactor selfie success LG-12159: Refactor selfie_success to selfie_status and make it return a symbol Jan 22, 2024
Comment on lines +13 to +17
:doc_auth_success, :selfie_success,
:doc_auth_success, :selfie_status,
keyword_init: true,
allowed_members: [:id, :success, :attention_with_barcode, :failed_front_image_fingerprints,
:failed_back_image_fingerprints, :captured_at, :selfie_check_performed,
:doc_auth_success, :selfie_success]
:doc_auth_success, :selfie_status]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this struct is serialized in redis, which means it will get persisted across hosts in a deploy. We need to add some 50-50 logic if we're renaming this, such as allowing both properties to be read, etc etc, then eventually dropping the old name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'll make a follow-up ticket to remove the old field and read from both fields in this PR. 👍🏻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up ticket: LG-12200

session_result.doc_auth_success = doc_auth_response.doc_auth_success?
# nil(selfie not required) or true/false
session_result.selfie_success = doc_auth_response.selfie_success
session_result.selfie_status = doc_auth_response.respond_to?(:selfie_status) ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileen-nava - whenever reading the selfie_status from DocumentCaptureResult, a string will be retrieved, yes? is there a way to return a symbol when retrieving the selfie_status attribute from DocumentCaptureResult?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileen-nava and @amirbey , one thought is that it can be achieved with a kind of subclass, or some kind of call backs
For example subclassing with prepend

require 'redacted_struct'
module TestPropSymbolizer
  def test_prop
    super.to_sym
  end
end
Result = RedactedStruct.new(

  :test_prop,
  allowed_members: [:test_prop],
) do

  prepend TestPropSymbolizer

end

t = Result.new(test_prop: 'abc')
puts t.test_prop
puts t.test_prop.class

Copy link
Contributor

@dawei-nava dawei-nava Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though it's debatable to include complex behaviors with struct, which basically a data holder.

Like hash in ruby, many cases it get overused it if not abuses.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a bit simpler ... i tried defining the method #selfie_status as follows in DocumentCaptureSessionResult which seemed to work ...

    def selfie_status
      self[:selfie_status].to_sym
    end

obs document_capture_session_result[:selfie_status] will still return a string, but using the member to fetch is not stylistically the way we're accessing attributes in this struct 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amirbey , that works too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dawei-nava @amirbey I implemented the first suggestion, then refreshed this thread and saw the second one. Is there a strong preference between the two? I agree that both work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileen-nava , no!

Copy link
Contributor

@dawei-nava dawei-nava Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileen-nava , we may need to consider accessing using result[:selfie_status] or result['selfie_status'] method calls
For example(draft):

def [](key)
    return super.to_sym if key.to_s == :test_prop
    super
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dawei-nava @amirbey I implemented the first suggestion, then refreshed this thread and saw the second one. Is there a strong preference between the two? I agree that both work.

I agree both work ... i prefer the latter approach for reasons stated here ... https://github.com/18F/identity-idp/pull/9953/files#r1465155665

@@ -0,0 +1,5 @@
module Symbolizer
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other names considered: StringToSymbolConverter or FieldSymbolizer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this concern be of use outside of DocumentCaptureSessionResult? I ask since Symbolizer doesn't seem closely tied to DocumentCaptureSessonResult; and, if other methods are added for use by other classes, the methods intended for use by other classes would be available to DocumentCaptureSessionResult and we would then maybe have to check the class of the caller. It almost seems like adding the #selfie_status method directly in DocumentCaptureSessionResult is a very simple solution and avoids this potential complication.

Comment on lines +469 to +470
selfie_status: client_response.respond_to?(:selfie_status) ?
client_response.selfie_status : :not_processed,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to help maintain consistency, this could be a private method reused on line 461:

...

selfie_status: selfie_status(client_response),

....

def selfie_status(client_response)
  return client_response.selfie_status if client_response.respond_to?(:selfie_status)

  :not_processed
end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amirbey I like this idea and took it one further by extracting the helper method into ApplicationHelper, so that we can use the method in ApiImageUploadForm, DocumentCaptureSession and DocAuth::Response.

'dcs:result'
end

def selfie_status
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similarly , result[:selfie_status] or result['selfie_status'] may have problem. But not critical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any scenarios in which we read session_result[:selfie_status] or session_result['selfie_status']? I thought we always used session_result.selfie_status.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileen-nava , no just for completeness purpose.

Copy link
Contributor

@dawei-nava dawei-nava left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@amirbey
Copy link
Contributor

amirbey commented Jan 24, 2024

@eileen-nava - LGTM ... do we want to add a quick test to ensure that document_capture_session_result.selfie_status returns a symbol? so this doesn't get mistakenly changed at a later time

Comment on lines +64 to +68
def selfie_status_from_response(client_response)
return client_response.selfie_status if client_response.respond_to?(:selfie_status)

:not_processed
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was this helper added here? this is a very generic helper, but this is a specific method? What if we made a mixin just for this?

end

def selfie_status_from_response(client_response)
return client_response.selfie_status if client_response.respond_to?(:selfie_status)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the respond_to? check how we are managing the 50-50 state?

If this code is running, it will be on a new box, so in that context, the selfie_status property will exist no matter what. I think we need to check the return values of the properties (because we really want to check the keys of the serialized JSON but that's hidden at this layer) so all we can see is which values are nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the respond_to? check how we are managing the 50-50 state?

No, it is not.

I referred to the existing documentation for renaming a field in a data structure in Redis, which states that in the first deploy, you add the new name and write to the new name everywhere the old name is written. I added selfie_success back to DocumentCaptureSessionResult in this commit and we will remove it when working on this ticket LG-12200

Please let me know if a different approach would be preferable.

Also, selfie_status_from_response takes a Response object like DocAuth::Response or Mock::ResultResponse. I thought the greatest risk around a 50/50 state error for this PR related to the change of a session field?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yup that's right, I lost track of which objects were deserialized from redis and which were just in-memory

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.

4 participants