Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Bringing UX to Your Code, V2

Bringing UX to Your Code, V2

User Centered Design as a process is almost thirty years old now. The philosophy has permeated our products and the way we build our interfaces. But this philosophy is rarely extended to the code we write. We'll take a look at some principles of UX and Interface Design and relate them back to our code. By comparing code that gets it right to code that gets it desperately wrong, we'll learn some principles that we can use to write more usable code.

Joseph Mastey

May 05, 2017
Tweet

More Decks by Joseph Mastey

Other Decks in Programming

Transcript

  1. @jmmastey Things We Ignore: 1. Anything invented a long time

    ago 2. Anything invented by non-engineers
  2. @jmmastey [:!, :!=, :!~, :<=>, :==, :===, :=~, :Pathname, :[],

    : []=, :__class__, :__extend__, :__id__, :__instance_variable_defined_p__, :__instance_variable_get__, :__instance_variable_set__, :__instance_variables__, :__marshal__, :__respond_to_p__, :__send__ , :__show__, :_commit_callbacks, :_commit_callbacks=, :_commit_callbacks?, :_create_callbacks, :_create_callbacks=, :_create_callbacks?, :_destroy, :_destroy_callbacks, :_destroy_callbacks=, :_des troy_callbacks?, :_find_callbacks, :_find_callbacks=, :_find_callbacks?, :_initialize_callbacks, :_initialize_callbacks=, :_initialize_callbacks?, :_read_attribute, :_reflections, :_reflections=, :_reflections?, :_rollback_callbacks, :_rollback_callbacks=, :_rollback_callbacks?, :_run_commit_callbacks, :_run_create_callbacks, :_run_destroy_callbacks, :_run_find_callbacks, :_run_initialize_ callbacks, :_run_rollback_callbacks, :_run_save_callbacks, :_run_touch_callbacks, :_run_update_callbacks, :_run_validate_callbacks, :_run_validation_callbacks, :_save_callbacks, :_save_callbacks=, :_save_callbacks?, :_touch_callbacks, :_touch_callbacks=, :_touch_callbacks?, :_update_callbacks, :_update_callbacks=, :_update_callbacks?, :_validate_callbacks, :_validate_callbacks=, :_validate_ callbacks?, :_validation_callbacks, :_validation_callbacks=, :_validation_callbacks?, :_validators, :_validators=, :_validators?, :`, :acts_like?, :actually_destroyed?, :add_to_transaction, :after _add_for_categories, :after_add_for_categories=, :after_add_for_categories?, :after_add_for_enrollments, :after_add_for_enrollments=, :after_add_for_enrollments?, :after_add_for_skills, :after_add _for_skills=, :after_add_for_skills?, :after_add_for_users, :after_add_for_users=, :after_add_for_users?, :after_remove_for_categories, :after_remove_for_categories=, :after_remove_for_categories? , :after_remove_for_enrollments, :after_remove_for_enrollments=, :after_remove_for_enrollments?, :after_remove_for_skills, :after_remove_for_skills=, :after_remove_for_skills?, :after_remove_for_u sers, :after_remove_for_users=, :after_remove_for_users?, :aggregate_reflections, :aggregate_reflections=, :aggregate_reflections?, :approve, :approve!, :approve_transition, :approved?, :arel_attr ibutes_with_values_for_create, :arel_attributes_with_values_for_update, :as_json, :assign_attributes, :association, :association_cache, :attribute_aliases, :attribute_aliases?, :attribute_changed? , :attribute_changed_in_place?, :attribute_for_inspect, :attribute_method?, :attribute_method_matchers, :attribute_method_matchers?, :attribute_missing, :attribute_names, :attribute_present?, :att ribute_was, :attributes, :attributes=, :attributes_before_type_cast, :attributes_changed_by_setter, :autosave_associated_records_for_categories, :autosave_associated_records_for_enrollments, :auto save_associated_records_for_skills, :autosave_associated_records_for_users, :becomes, :becomes!, :before_add_for_categories, :before_add_for_categories=, :before_add_for_categories?, :before_add_f or_enrollments, :before_add_for_enrollments=, :before_add_for_enrollments?, :before_add_for_skills, :before_add_for_skills=, :before_add_for_skills?, :before_add_for_users, :before_add_for_users=, :before_add_for_users?, :before_remove_for_categories, :before_remove_for_categories=, :before_remove_for_categories?, :before_remove_for_enrollments, :before_remove_for_enrollments=, :before_remo ve_for_enrollments?, :before_remove_for_skills, :before_remove_for_skills=, :before_remove_for_skills?, :before_remove_for_users, :before_remove_for_users=, :before_remove_for_users?, :blank?, :ca che_key, :cache_timestamp_format, :cache_timestamp_format?, :can_approve?, :can_deprecate?, :can_hide?, :can_publish?, :capture, :categories, :categories=, :category_ids, :category_ids=, :changed, :changed?, :changed_attributes, :changed_for_autosave?, :changes, :changes_applied, :class, :class_eval, :clear_aggregation_cache, :clear_association_cache, :clear_changes_information, :clear_dest roy_state, :clear_transaction_record_state, :clone, :clone_attribute_value, :column_for_attribute, :committed!, :concern, :connection_handler, :created?, :created_at, :created_at=, :created_at?, : created_at_before_type_cast, :created_at_change, :created_at_changed?, :created_at_was, :created_at_will_change!, :decrement, :decrement!, :deep_dup, :default_connection_handler, :default_connecti on_handler?, :default_scopes, :default_timezone, :define_singleton_method, :defined_enums, :defined_enums=, :defined_enums?, :delete, :deprecate, :deprecate!, :deprecate_transition, :deprecated?, :description, :description=, :description?, :description_before_type_cast, :description_change, :description_changed?, :description_was, :description_will_change!, :destroy, :destroy!, :destroyed? , :destroyed_by_association, :destroyed_by_association=, :display, :dump_schema_after_migration, :dup, :duplicable?, :enable_warnings, :encode_with, :enrollment_ids, :enrollment_ids=, :enrollments , :enrollments=, :enum_for, :eql?, :equal?, :error_on, :errors, :errors_on, :extend, :find_by_statement_cache, :find_by_statement_cache=, :find_by_statement_cache?, :fire_events, :fire_events!, :f ire_status_event, :force_clear_transaction_record_state, :freeze, :from_json, :from_xml, :frozen?, :gem, :handle, :handle=, :handle?, :handle_before_type_cast, :handle_change, :handle_changed?, :h andle_was, :handle_will_change!, :has_attribute?, :has_transactional_callbacks?, :hash, :hidden?, :hide, :hide!, :hide_transition, :html_safe?, :human_status_name, :id, :id=, :id?, :id_before_type _cast, :id_change, :id_changed?, :id_was, :id_will_change!, :in?, :include_root_in_json, :include_root_in_json=, :include_root_in_json?, :increment, :increment!, :init_with, :initialize_internals_ callback, :initialize_state_machines, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_values, :instance_variable_defined?, :instance_variable_get, :instance_variable_names, :ins tance_variable_set, :instance_variables, :invalid?, :is_a?, :is_haml?, :itself, :kind_of?, :load_dependency, :lock!, :lock_optimistically, :lock_optimistically?, :locking_enabled?, :logger, :mark_ for_destruction, :marked_for_destruction?, :method, :method_missing, :methods, :model_name, :name, :name=, :name?, :name_before_type_cast, :name_change, :name_changed?, :name_was, :name_will_chang e!, :nested_attributes_options, :nested_attributes_options?, :new_record?, :nil?, :no_touching?, :object_id, :organization, :organization=, :organization?, :organization_before_type_cast, :organiz ation_change, :organization_changed?, :organization_was, :organization_will_change!, :partial_writes, :partial_writes?, :perform_validations, :persisted?, :pluralize_table_names, :pluralize_table_ names?, :populate_with_current_scope_attributes, :presence, :presence_in, :present?, :pretty_inspect, :pretty_print, :pretty_print_cycle, :pretty_print_inspect, :pretty_print_instance_variables, : previous_changes, :primary_key_prefix_type, :private_methods, :protected_methods, :public_method, :public_methods, :public_send, :publish, :publish!, :publish_transition, :published?, :query_attri bute, :quietly, :quietly_with_deprecation_silenced, :quietly_without_deprecation_silenced, :quoted_id, :raise_in_transactional_callbacks, :raise_record_invalid, :read_attribute, :read_attribute_be fore_type_cast, :read_attribute_for_serialization, :read_attribute_for_validation, :read_store_attribute, :readonly!, :readonly?, :record_timestamps, :record_timestamps=, :record_timestamps?, :rel oad, :remember_transaction_record_state, :remove_instance_variable, :require_dependency, :require_or_load, :reset_created_at!, :reset_description!, :reset_handle!, :reset_id!, :reset_name!, :reset _organization!, :reset_status!, :reset_updated_at!, :respond_to?, :respond_to_without_attributes?, :restore_attributes, :restore_created_at!, :restore_description!, :restore_handle!, :restore_id!, :restore_name!, :restore_organization!, :restore_status!, :restore_transaction_record_state, :restore_updated_at!, :rollback_active_record_state!, :rolledback!, :run_callbacks, :run_validations!, :sanitize_for_mass_assignment, :sanitize_forbidden_attributes, :save, :save!, :schema_format, :send, :serializable_hash, :set_transaction_state, :should, :should_not, :silence, :silence_stderr, :s ilence_stream, :silence_warnings, :singleton_class, :singleton_class?, :singleton_methods, :skill_ids, :skill_ids=, :skills, :skills=, :skip_time_zone_conversion_for_attributes, :skip_time_zone_co nversion_for_attributes?, :slice, :status, :status=, :status?, :status_before_type_cast, :status_change, :status_changed?, :status_event, :status_event=, :status_event_transition, :status_event_tr ansition=, :status_events, :status_name, :status_paths, :status_transitions, :status_was, :status_will_change!, :store_full_sti_class, :store_full_sti_class?, :suppress, :suppress_warnings, :syck_ to_yaml, :table_name_prefix, :table_name_prefix?, :table_name_suffix, :table_name_suffix?, :taguri, :taguri=, :taint, :tainted?, :tap, :time_zone_aware_attributes, :timestamped_migrations, :to_enu m, :to_gid, :to_global_id, :to_json, :to_json_with_active_support_encoder, :to_json_without_active_support_encoder, :to_key, :to_model, :to_param, :to_partial_path, :to_query, :to_s, :to_sgid, :to _signed_global_id, :to_xml, :to_yaml, :to_yaml_properties, :to_yaml_style, :toggle, :toggle!, :touch, :transaction, :transaction_include_any_action?, :transaction_record_state, :trust, :try, :try! , :type_for_attribute, :unloadable, :untaint, :untrust, :untrusted?, :update, :update!, :update_attribute, :update_attributes, :update_attributes!, :update_column, :update_columns, :updated_at, :u pdated_at=, :updated_at?, :updated_at_before_type_cast, :updated_at_change, :updated_at_changed?, :updated_at_was, :updated_at_will_change!, :user_ids, :user_ids=, :users, :users=, :valid?, :valid ate, :validate!, :validate_associated_records_for_categories, :validate_associated_records_for_enrollments, :validate_associated_records_for_skills, :validate_associated_records_for_users, :valida tes_absence_of, :validates_acceptance_of, :validates_confirmation_of, :validates_exclusion_of, :validates_format_of, :validates_inclusion_of, :validates_length_of, :validates_numericality_of, :val idates_presence_of, :validates_size_of, :validates_with, :validation_context, :validation_context=, :with_lock, :with_options, :with_transaction_returning_status, :with_warnings, :write_store_attr ibute]
  3. HTTP Verb: DELETE SQL Statement: DELETE FROM * Arrays: delete,

    delete_at, delete_if Every OS Ever: DELETE
  4. @jmmastey params = { product_code: “foO” } # do work

    expect(macguffin.upc).to eq(“FOO”)
  5. @jmmastey [:!, :!=, :!~, :<=>, :==, :===, :=~, :Pathname, :[],

    : []=, :__class__, :__extend__, :__id__, :__instance_variable_defined_p__, :__instance_variable_get__, :__instance_variable_set__, :__instance_variables__, :__marshal__, :__respond_to_p__, :__send__ , :__show__, :_commit_callbacks, :_commit_callbacks=, :_commit_callbacks?, :_create_callbacks, :_create_callbacks=, :_create_callbacks?, :_destroy, :_destroy_callbacks, :_destroy_callbacks=, :_des troy_callbacks?, :_find_callbacks, :_find_callbacks=, :_find_callbacks?, :_initialize_callbacks, :_initialize_callbacks=, :_initialize_callbacks?, :_read_attribute, :_reflections, :_reflections=, :_reflections?, :_rollback_callbacks, :_rollback_callbacks=, :_rollback_callbacks?, :_run_commit_callbacks, :_run_create_callbacks, :_run_destroy_callbacks, :_run_find_callbacks, :_run_initialize_ callbacks, :_run_rollback_callbacks, :_run_save_callbacks, :_run_touch_callbacks, :_run_update_callbacks, :_run_validate_callbacks, :_run_validation_callbacks, :_save_callbacks, :_save_callbacks=, :_save_callbacks?, :_touch_callbacks, :_touch_callbacks=, :_touch_callbacks?, :_update_callbacks, :_update_callbacks=, :_update_callbacks?, :_validate_callbacks, :_validate_callbacks=, :_validate_ callbacks?, :_validation_callbacks, :_validation_callbacks=, :_validation_callbacks?, :_validators, :_validators=, :_validators?, :`, :acts_like?, :actually_destroyed?, :add_to_transaction, :after _add_for_categories, :after_add_for_categories=, :after_add_for_categories?, :after_add_for_enrollments, :after_add_for_enrollments=, :after_add_for_enrollments?, :after_add_for_skills, :after_add _for_skills=, :after_add_for_skills?, :after_add_for_users, :after_add_for_users=, :after_add_for_users?, :after_remove_for_categories, :after_remove_for_categories=, :after_remove_for_categories? , :after_remove_for_enrollments, :after_remove_for_enrollments=, :after_remove_for_enrollments?, :after_remove_for_skills, :after_remove_for_skills=, :after_remove_for_skills?, :after_remove_for_u sers, :after_remove_for_users=, :after_remove_for_users?, :aggregate_reflections, :aggregate_reflections=, :aggregate_reflections?, :approve, :approve!, :approve_transition, :approved?, :arel_attr ibutes_with_values_for_create, :arel_attributes_with_values_for_update, :as_json, :assign_attributes, :association, :association_cache, :attribute_aliases, :attribute_aliases?, :attribute_changed? , :attribute_changed_in_place?, :attribute_for_inspect, :attribute_method?, :attribute_method_matchers, :attribute_method_matchers?, :attribute_missing, :attribute_names, :attribute_present?, :att ribute_was, :attributes, :attributes=, :attributes_before_type_cast, :attributes_changed_by_setter, :autosave_associated_records_for_categories, :autosave_associated_records_for_enrollments, :auto save_associated_records_for_skills, :autosave_associated_records_for_users, :becomes, :becomes!, :before_add_for_categories, :before_add_for_categories=, :before_add_for_categories?, :before_add_f or_enrollments, :before_add_for_enrollments=, :before_add_for_enrollments?, :before_add_for_skills, :before_add_for_skills=, :before_add_for_skills?, :before_add_for_users, :before_add_for_users=, :before_add_for_users?, :before_remove_for_categories, :before_remove_for_categories=, :before_remove_for_categories?, :before_remove_for_enrollments, :before_remove_for_enrollments=, :before_remo ve_for_enrollments?, :before_remove_for_skills, :before_remove_for_skills=, :before_remove_for_skills?, :before_remove_for_users, :before_remove_for_users=, :before_remove_for_users?, :blank?, :ca che_key, :cache_timestamp_format, :cache_timestamp_format?, :can_approve?, :can_deprecate?, :can_hide?, :can_publish?, :capture, :categories, :categories=, :category_ids, :category_ids=, :changed, :changed?, :changed_attributes, :changed_for_autosave?, :changes, :changes_applied, :class, :class_eval, :clear_aggregation_cache, :clear_association_cache, :clear_changes_information, :clear_dest roy_state, :clear_transaction_record_state, :clone, :clone_attribute_value, :column_for_attribute, :committed!, :concern, :connection_handler, :created?, :created_at, :created_at=, :created_at?, : created_at_before_type_cast, :created_at_change, :created_at_changed?, :created_at_was, :created_at_will_change!, :decrement, :decrement!, :deep_dup, :default_connection_handler, :default_connecti on_handler?, :default_scopes, :default_timezone, :define_singleton_method, :defined_enums, :defined_enums=, :defined_enums?, :delete, :deprecate, :deprecate!, :deprecate_transition, :deprecated?, :description, :description=, :description?, :description_before_type_cast, :description_change, :description_changed?, :description_was, :description_will_change!, :destroy, :destroy!, :destroyed? , :destroyed_by_association, :destroyed_by_association=, :display, :dump_schema_after_migration, :dup, :duplicable?, :enable_warnings, :encode_with, :enrollment_ids, :enrollment_ids=, :enrollments , :enrollments=, :enum_for, :eql?, :equal?, :error_on, :errors, :errors_on, :extend, :find_by_statement_cache, :find_by_statement_cache=, :find_by_statement_cache?, :fire_events, :fire_events!, :f ire_status_event, :force_clear_transaction_record_state, :freeze, :from_json, :from_xml, :frozen?, :gem, :handle, :handle=, :handle?, :handle_before_type_cast, :handle_change, :handle_changed?, :h andle_was, :handle_will_change!, :has_attribute?, :has_transactional_callbacks?, :hash, :hidden?, :hide, :hide!, :hide_transition, :html_safe?, :human_status_name, :id, :id=, :id?, :id_before_type _cast, :id_change, :id_changed?, :id_was, :id_will_change!, :in?, :include_root_in_json, :include_root_in_json=, :include_root_in_json?, :increment, :increment!, :init_with, :initialize_internals_ callback, :initialize_state_machines, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_values, :instance_variable_defined?, :instance_variable_get, :instance_variable_names, :ins tance_variable_set, :instance_variables, :invalid?, :is_a?, :is_haml?, :itself, :kind_of?, :load_dependency, :lock!, :lock_optimistically, :lock_optimistically?, :locking_enabled?, :logger, :mark_ for_destruction, :marked_for_destruction?, :method, :method_missing, :methods, :model_name, :name, :name=, :name?, :name_before_type_cast, :name_change, :name_changed?, :name_was, :name_will_chang e!, :nested_attributes_options, :nested_attributes_options?, :new_record?, :nil?, :no_touching?, :object_id, :organization, :organization=, :organization?, :organization_before_type_cast, :organiz ation_change, :organization_changed?, :organization_was, :organization_will_change!, :partial_writes, :partial_writes?, :perform_validations, :persisted?, :pluralize_table_names, :pluralize_table_ names?, :populate_with_current_scope_attributes, :presence, :presence_in, :present?, :pretty_inspect, :pretty_print, :pretty_print_cycle, :pretty_print_inspect, :pretty_print_instance_variables, : previous_changes, :primary_key_prefix_type, :private_methods, :protected_methods, :public_method, :public_methods, :public_send, :publish, :publish!, :publish_transition, :published?, :query_attri bute, :quietly, :quietly_with_deprecation_silenced, :quietly_without_deprecation_silenced, :quoted_id, :raise_in_transactional_callbacks, :raise_record_invalid, :read_attribute, :read_attribute_be fore_type_cast, :read_attribute_for_serialization, :read_attribute_for_validation, :read_store_attribute, :readonly!, :readonly?, :record_timestamps, :record_timestamps=, :record_timestamps?, :rel oad, :remember_transaction_record_state, :remove_instance_variable, :require_dependency, :require_or_load, :reset_created_at!, :reset_description!, :reset_handle!, :reset_id!, :reset_name!, :reset _organization!, :reset_status!, :reset_updated_at!, :respond_to?, :respond_to_without_attributes?, :restore_attributes, :restore_created_at!, :restore_description!, :restore_handle!, :restore_id!, :restore_name!, :restore_organization!, :restore_status!, :restore_transaction_record_state, :restore_updated_at!, :rollback_active_record_state!, :rolledback!, :run_callbacks, :run_validations!, :sanitize_for_mass_assignment, :sanitize_forbidden_attributes, :save, :save!, :schema_format, :send, :serializable_hash, :set_transaction_state, :should, :should_not, :silence, :silence_stderr, :s ilence_stream, :silence_warnings, :singleton_class, :singleton_class?, :singleton_methods, :skill_ids, :skill_ids=, :skills, :skills=, :skip_time_zone_conversion_for_attributes, :skip_time_zone_co nversion_for_attributes?, :slice, :status, :status=, :status?, :status_before_type_cast, :status_change, :status_changed?, :status_event, :status_event=, :status_event_transition, :status_event_tr ansition=, :status_events, :status_name, :status_paths, :status_transitions, :status_was, :status_will_change!, :store_full_sti_class, :store_full_sti_class?, :suppress, :suppress_warnings, :syck_ to_yaml, :table_name_prefix, :table_name_prefix?, :table_name_suffix, :table_name_suffix?, :taguri, :taguri=, :taint, :tainted?, :tap, :time_zone_aware_attributes, :timestamped_migrations, :to_enu m, :to_gid, :to_global_id, :to_json, :to_json_with_active_support_encoder, :to_json_without_active_support_encoder, :to_key, :to_model, :to_param, :to_partial_path, :to_query, :to_s, :to_sgid, :to _signed_global_id, :to_xml, :to_yaml, :to_yaml_properties, :to_yaml_style, :toggle, :toggle!, :touch, :transaction, :transaction_include_any_action?, :transaction_record_state, :trust, :try, :try! , :type_for_attribute, :unloadable, :untaint, :untrust, :untrusted?, :update, :update!, :update_attribute, :update_attributes, :update_attributes!, :update_column, :update_columns, :updated_at, :u pdated_at=, :updated_at?, :updated_at_before_type_cast, :updated_at_change, :updated_at_changed?, :updated_at_was, :updated_at_will_change!, :user_ids, :user_ids=, :users, :users=, :valid?, :valid ate, :validate!, :validate_associated_records_for_categories, :validate_associated_records_for_enrollments, :validate_associated_records_for_skills, :validate_associated_records_for_users, :valida tes_absence_of, :validates_acceptance_of, :validates_confirmation_of, :validates_exclusion_of, :validates_format_of, :validates_inclusion_of, :validates_length_of, :validates_numericality_of, :val idates_presence_of, :validates_size_of, :validates_with, :validation_context, :validation_context=, :with_lock, :with_options, :with_transaction_returning_status, :with_warnings, :write_store_attr ibute]
  6. @jmmastey 㽩 /export/nonce (master) > rspec bomb_spec.rb Failures: 1) MyObject

    works at all Failure/Error: expect(1).to eq(0) expected: 0 got: 1 … stacktrace … Finished in 0.00375 seconds (files took 0.29196 seconds to load) 1 example, 1 failure Failed examples: rspec ./bomb_spec.rb:4 # MyObject works at all
  7. @jmmastey 㽩 /export/nonce (master) > rspec bomb_spec.rb Failures: 1) MyObject

    works at all Failure/Error: expect(1).to eq(0) expected: 0 got: 1 … stacktrace … Finished in 0.00375 seconds (files took 0.29196 seconds to load) 1 example, 1 failure Failed examples: rspec ./bomb_spec.rb:4 # MyObject works at all
  8. @jmmastey 㽩 /export/nonce (master) > rspec bomb_spec.rb Failures: 1) MyObject

    works at all Failure/Error: expect(1).to eq(0) expected: 0 got: 1 … stacktrace … Finished in 0.00375 seconds (files took 0.29196 seconds to load) 1 example, 1 failure Failed examples: rspec ./bomb_spec.rb:4 # MyObject works at all
  9. @jmmastey “The world is filled with plenty of anguish —

    make your life goal not to add to it.”
  10. @jmmastey “So you wanna be a user experience designer” -

    Whitney Hess (http://bit.ly/1Hn1nQS) “The Design of Everyday Things” - Don Norman (I dunno, Amazon?)
  11. @jmmastey Thanks! Frustration Photo by jseliger2 (https://www.flickr.com/photos/91262622@N02/) Happy Kids by

    deepblue66 (https://www.flickr.com/photos/deepblue66/14503838952) Annotated code by Avdi Grimm (https://avdi.org) All icons from the NounProject (https://nounproject.com)