I Know I Can, But Should I? Evaluating Alternatives

I Know I Can, But Should I? Evaluating Alternatives

You can use a hammer to drive a screw into wood, but I’d recommend a screwdriver. Why? And when is a hammer the better option? This talk will propose a framework to use when comparing alternative technical choices. I won’t decide for you, but will leave you with a structure to apply in your decision-making process.

The ruby toolbox is vast. While Rails provides a default experience, it leaves plenty of room for alternatives. In learning how to do something, you may uncover different ways to accomplish the same goal. Determine which tool fits best in your situation with these lessons.

B2f82edebc6e840ed97c8606700d123a?s=128

Kevin Murphy

April 09, 2019
Tweet

Transcript

  1. @kevin_j_m I Know I Can, But Should I? Evaluating Alternatives

    Kevin Murphy
  2. @kevin_j_m

  3. @kevin_j_m

  4. @kevin_j_m

  5. @kevin_j_m Why?

  6. @kevin_j_m Experience

  7. @kevin_j_m Speed

  8. @kevin_j_m Difficulty

  9. @kevin_j_m Interest

  10. @kevin_j_m Gut Reaction

  11. @kevin_j_m @kevin_j_m Kevin Murphy

  12. @kevin_j_m Weighted Scoring Model

  13. @kevin_j_m Weighted Scoring Model

  14. @kevin_j_m Weighted Scoring Model Criteria

  15. @kevin_j_m Price Weighted Scoring Model Criteria

  16. @kevin_j_m Price Ease of Use Weighted Scoring Model Criteria

  17. @kevin_j_m Price Ease of Use Compliance Weighted Scoring Model Criteria

  18. @kevin_j_m Price Ease of Use Compliance Delivery Time Weighted Scoring

    Model Criteria
  19. @kevin_j_m Price Ease of Use Compliance Delivery Time Weighted Scoring

    Model Criteria Weight
  20. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% Weighted Scoring Model Criteria Weight
  21. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% A Weighted Scoring Model Criteria Weight
  22. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% A B Weighted Scoring Model Criteria Weight
  23. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% A B 8 2 5 3 Weighted Scoring Model Criteria Weight
  24. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% A B 8 2 5 3 3 5 7 4 Weighted Scoring Model Criteria Weight
  25. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% A B 8 2 5 3 3 5 7 4 4.8 Weighted Scoring Model Criteria Weight
  26. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% A B 8 2 5 3 3 5 7 4 4.8 4.4 Weighted Scoring Model Criteria Weight
  27. @kevin_j_m Price Ease of Use Compliance Delivery Time 30% 10%

    20% 40% A B 8 2 5 3 3 5 7 4 4.8 4.4 Weighted Scoring Model Criteria Weight
  28. @kevin_j_m Merits Thoughtful

  29. @kevin_j_m Merits Justification ⚖

  30. @kevin_j_m Merits Consensus

  31. @kevin_j_m Limitations Time ⏰

  32. @kevin_j_m Limitations Knowledge

  33. @kevin_j_m Limitations Inflexible

  34. @kevin_j_m

  35. @kevin_j_m Impact Cost Maintenance Consistency

  36. @kevin_j_m

  37. @kevin_j_m Impact

  38. @kevin_j_m ' (

  39. @kevin_j_m Send Welcome Email Send a welcome email to a

    study participant after they have enrolled.
  40. @kevin_j_m scenario “Enrolling a participant” do end

  41. @kevin_j_m scenario “Enrolling a participant” do visit new_study_participant_path(study) end

  42. @kevin_j_m scenario “Enrolling a participant” do visit new_study_participant_path(study) fill_in "First

    name", with: "Kevin" fill_in "Email", with: "hi@thegnar.co" end
  43. @kevin_j_m scenario “Enrolling a participant” do visit new_study_participant_path(study) fill_in "First

    name", with: "Kevin" fill_in "Email", with: "hi@thegnar.co" expect { click_button "Enroll" } .to have_enqueued_job .on_queue(“mailers”) end
  44. @kevin_j_m class StudyParticipant < ApplicationRecord private end

  45. @kevin_j_m class StudyParticipant < ApplicationRecord after_commit :deliver_welcome_mailer, on: :create private

    end +
  46. @kevin_j_m class StudyParticipant < ApplicationRecord after_commit :deliver_welcome_mailer, on: :create private

    def deliver_welcome_mailer end end + + +
  47. @kevin_j_m class StudyParticipant < ApplicationRecord after_commit :deliver_welcome_mailer, on: :create private

    def deliver_welcome_mailer StudyParticipantMailer.with(study_participant: self) .welcome_email .deliver_later end end + + + + + +
  48. @kevin_j_m $ rspec . Finished in 0.01783 seconds 1 example,

    0 failures
  49. @kevin_j_m $ git reset --hard

  50. @kevin_j_m class StudyEnrollment end

  51. @kevin_j_m class StudyEnrollment def initialize(participant_params) @participant_params = participant_params end end

  52. @kevin_j_m class StudyEnrollment def initialize(participant_params) @participant_params = participant_params end def

    save end end
  53. @kevin_j_m class StudyEnrollment def initialize(participant_params) @participant_params = participant_params end def

    save @study_participant = StudyParticipant.new(@participant_params) end end
  54. @kevin_j_m class StudyEnrollment def initialize(participant_params) @participant_params = participant_params end def

    save @study_participant = StudyParticipant.new(@participant_params) if @study_participant.save send_welcome_email end end end
  55. @kevin_j_m class StudyParticipantsController < ApplicationController def create @study_participant = StudyParticipant.new(

    study_participant_params) if @study_participant.save redirect_to study_study_participants_path else render :new end end end
  56. @kevin_j_m class StudyParticipantsController < ApplicationController def create enrollment = StudyEnrollment.new(

    study_participant_params) if @study_participant.save redirect_to study_study_participants_path else render :new end end end +
  57. @kevin_j_m class StudyParticipantsController < ApplicationController def create enrollment = StudyEnrollment.new(

    study_participant_params) if enrollment.save redirect_to study_study_participants_path else render :new end end end + +
  58. @kevin_j_m class StudyParticipantsController < ApplicationController def create enrollment = StudyEnrollment.new(

    study_participant_params) if enrollment.save redirect_to study_study_participants_path else @study_participant = enrollment.study_participant render :new end end end + + +
  59. @kevin_j_m $ rspec . Finished in 0.01437 seconds 1 example,

    0 failures
  60. @kevin_j_m Impact Team Reaction ☢

  61. @kevin_j_m Impact Future Standard

  62. @kevin_j_m Impact Non-Functional Requirements

  63. @kevin_j_m Cost

  64. @kevin_j_m Limit System Access Ensure that only Principal Investigators may

    create study protocols.
  65. @kevin_j_m scenario “Co-investigators cannot create a study protocol” do end

  66. @kevin_j_m scenario “Co-investigators cannot create a study protocol” do sign_in

    co_investigator_user end
  67. @kevin_j_m scenario “Co-investigators cannot create a study protocol” do sign_in

    co_investigator_user visit new_study_protocol_path(study) end
  68. @kevin_j_m scenario “Co-investigators cannot create a study protocol” do sign_in

    co_investigator_user visit new_study_protocol_path(study) within(".alert-danger") do expect(page).to have_content "Only Principal Investigators may create study protocols" end end
  69. @kevin_j_m scenario “Co-investigators cannot create a study protocol” do sign_in

    co_investigator_user visit new_study_protocol_path(study) within(".alert-danger") do expect(page).to have_content "Only Principal Investigators may create study protocols" end expect(page).to have_current_path root_path end
  70. @kevin_j_m class StudyProtocolsController < ApplicationController def new @study_protocol = StudyProtocol.new(study:

    study) end end
  71. @kevin_j_m class StudyProtocolsController < ApplicationController def new if current_user.principal_investigator? @study_protocol

    = StudyProtocol.new(study: study) end end end + + +
  72. @kevin_j_m class StudyProtocolsController < ApplicationController def new if current_user.principal_investigator? @study_protocol

    = StudyProtocol.new(study: study) else user_not_authorized end end end + + + + +
  73. @kevin_j_m $ rspec . Finished in 0.02832 seconds 1 example,

    0 failures
  74. @kevin_j_m $ git reset --hard

  75. @kevin_j_m class StudyProtocolsController < ApplicationController def new @study_protocol = StudyProtocol.new(study:

    study) end end
  76. @kevin_j_m class StudyProtocolsController < ApplicationController def new @study_protocol = StudyProtocol.new(study:

    study) authorize(@study_protocol) end end +
  77. @kevin_j_m class StudyProtocolsController < ApplicationController rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized def

    new @study_protocol = StudyProtocol.new(study: study) authorize(@study_protocol) end end + + +
  78. @kevin_j_m $ rspec . Finished in 0.02146 seconds 1 example,

    0 failures
  79. @kevin_j_m Cost

  80. @kevin_j_m Cost Risk Appetite

  81. @kevin_j_m Cost Contextual Pressures ⌛

  82. @kevin_j_m Cost Big Picture

  83. @kevin_j_m Maintenance

  84. @kevin_j_m Data Collection Date Display the date when data was

    collected along with the data.
  85. @kevin_j_m scenario “Viewing a data collection event” do end

  86. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) end
  87. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) collection_event = create :data_collection_event, created_at: collected_at end
  88. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) collection_event = create :data_collection_event, created_at: collected_at visit data_collection_event_path(collection_event) end
  89. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) collection_event = create :data_collection_event, created_at: collected_at visit data_collection_event_path(collection_event) within ".summary-information .collected-date" do expect(page).to have_content "May 1, 2019" end end
  90. @kevin_j_m <dl> </dl>

  91. @kevin_j_m <dl> <dt>Collection Date:</dt> </dl>

  92. @kevin_j_m <dl> <dt>Collection Date:</dt> <dd class=“collected-date"> </dd> </dl>

  93. @kevin_j_m <dl> <dt>Collection Date:</dt> <dd class=“collected-date"> <%= l(@data_collection_event.created_at, format: :long_date_only)%>

    </dd> </dl>
  94. @kevin_j_m $ rspec . Finished in 0.01126 seconds 1 example,

    0 failures
  95. @kevin_j_m $ git reset --hard

  96. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) collection_event = create :data_collection_event, created_at: collected_at visit data_collection_event_path(collection_event) within ".summary-information .collected-date" do expect(page).to have_content "May 1, 2019" end end
  97. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) collection_event = create :data_collection_event, created_at: collected_at visit data_collection_event_path(collection_event) within ".summary-information .collected-date" do expect(page).to have_content "May 1, 2019" end end
  98. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) collection_event = create :data_collection_event, created_at: collected_at visit data_collection_event_path(collection_event) within ".summary-information .collected-date" do expect(page).to have_content "May 1, 2019" end end
  99. @kevin_j_m scenario “Viewing a data collection event” do collected_at =

    Time.zone.local(2019, 5, 1, 15, 30) collection_event = create :data_collection_event, collected_at: collected_at visit data_collection_event_path(collection_event) within ".summary-information .collected-date" do expect(page).to have_content "May 1, 2019" end end
  100. @kevin_j_m $ rails g migration add_collected_at_to_data_collection

  101. @kevin_j_m <dl> <dt>Collection Date:</dt> <dd class=“collected-date"> <%= l(@data_collection_event.created_at, format: :long_date_only)%>

    </dd> </dl>
  102. @kevin_j_m <dl> <dt>Collection Date:</dt> <dd class=“collected-date"> <%= l(@data_collection_event.created_at, format: :long_date_only)%>

    </dd> </dl>
  103. @kevin_j_m <dl> <dt>Collection Date:</dt> <dd class=“collected-date"> <%= l(@data_collection_event.collected_at, format: :long_date_only)%>

    </dd> </dl>
  104. @kevin_j_m $ rspec . Finished in 0.01283 seconds 1 example,

    0 failures
  105. @kevin_j_m Maintenance Upcoming Requirements

  106. @kevin_j_m Maintenance Solicit Input 1

  107. @kevin_j_m Maintenance Future Self

  108. @kevin_j_m Consistency

  109. @kevin_j_m Personal Info Warning Warn a user that editing their

    personal information may make them ineligible for the study.
  110. @kevin_j_m scenario “Warn about personal information changes” do end

  111. @kevin_j_m scenario “Warn about personal information changes” do visit edit_personal_information_path(participant)

    end
  112. @kevin_j_m scenario “Warn about personal information changes” do visit edit_personal_information_path(participant)

    within(".alert-warning") do end end
  113. @kevin_j_m scenario “Warn about personal information changes” do visit edit_personal_information_path(participant)

    within(".alert-warning") do expect(page).to have_content “Modifying your information may risk your eligibility.” end end
  114. @kevin_j_m class PersonalInformationController < ApplicationController def edit @personal_information = PersonalInformation.new(id)

    end end
  115. @kevin_j_m class PersonalInformationController < ApplicationController def edit @personal_information = PersonalInformation.new(id)

    flash[:warning] = I18n.t(“personal_info.edit.warning”) end end +
  116. @kevin_j_m $ rspec . Finished in 0.01427 seconds 1 example,

    0 failures
  117. @kevin_j_m

  118. @kevin_j_m class PersonalInformationController < ApplicationController def edit @personal_information = PersonalInformation.new(id)

    flash[:warning] = I18n.t(“personal_info.edit.warning”) end end +
  119. @kevin_j_m scenario “Warn about personal information changes” do visit edit_personal_information_path(participant)

    within(".alert-warning") do expect(page).to have_content “Modifying your information may risk your eligibility.” end end - - - - - - - -
  120. @kevin_j_m Consistency Institutional Knowledge

  121. @kevin_j_m Consistency Existing Standards

  122. @kevin_j_m Consistency Orientation Time

  123. @kevin_j_m Impact Cost Maintenance Consistency

  124. @kevin_j_m Current Applicability

  125. @kevin_j_m Impact Cost Maintenance Consistency

  126. @kevin_j_m Impact Cost Maintenance Consistency 30% 10% 20% 40%

  127. @kevin_j_m Personal Info Warning Per FDA RC2019-PII, warn a user

    that editing their personal information may make them ineligible for the study.
  128. @kevin_j_m Impact Cost Maintenance Consistency 30% 10% 20% 40%

  129. @kevin_j_m Impact Cost Maintenance Consistency 40% 10% 30% 20%

  130. @kevin_j_m RC2019-PII …Failure to notify participants of this may be

    punishable by up to 30 days in jail or fines of $1,000,000 per documented occurrence.
  131. @kevin_j_m Impact Cost Maintenance Consistency 40% 10% 30% 20%

  132. @kevin_j_m Impact Cost Maintenance Consistency 15% 70% 10% 5%

  133. @kevin_j_m scenario “Editing Personal Information” do visit edit_personal_information_path(participant) fill_in “First

    Name”, with: “Kevin” click_button “Submit” … end
  134. @kevin_j_m scenario “Editing Personal Information” do visit edit_personal_information_path(participant) within(".alert-warning") do

    expect(page).to have_content "Modifying your information your may risk your eligibility.” end fill_in “First Name”, with: “Kevin” … end + + + +
  135. @kevin_j_m Impact Cost Maintenance Consistency

  136. @kevin_j_m https://www.thegnar.co/railsconf https://github.com/kevin-j-m/evaluating-alternatives

  137. @kevin_j_m @kevin_j_m Kevin Murphy