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

Writing Loveable Code

Writing Loveable Code

Join me on my journey from thinking that the best code is clever and elegant to realizing that code that makes your fellow developers happy should be your goal.We will start with code that has a high barrier of entry and make changes to make it more easily testable, understandable, and extendable.

Avatar for Seema Ullal

Seema Ullal

August 02, 2018

Other Decks in Technology

Transcript

  1. I hope to see Ruby help every programmer in the

    world to be productive, and to enjoy programming, and to be happy. That is the primary purpose of Ruby language. — Yukihiro Matsumoto @seemaisms [email protected]
  2. ! : "Let's make this even better" ! : "Sounds

    great, I'll start implementing those changes" @seemaisms [email protected]
  3. class Connect4 def initialize @board = ("......\n"*7).chomp @player = "2"

    @done = false end def play col return "Game has finished!" if @done begin @board[%r/\A((......\n){#{col}}\d*)(\.)/, 3] = "#@player" rescue return "Column full!" end @player.tr! "12", "21" if [0,5,6,7].any?{|off| @board =~ /(\d)([\s\S]{#{off}}\1){3}/} @done = true "Player #@player wins!" else "Player #@player has a turn" end end end @seemaisms [email protected]
  4. class Connect4 def initialize @board = initialize_board @turn = 1

    @finished = false end def play(row_index) @row_index = row_index return 'Game has finished!' if @finished return "Column full!" if column_full? @board[@row_index] << @turn if player_won? @finished = true return "Player #{@turn} wins!" else toggle_turn return "Player #{@turn == 1 ? 2 : 1} has a turn" end end @seemaisms [email protected]
  5. def toggle_turn @turn = @turn == 1 ? 2 :

    1 end def player_won? four_in_a_row?(vertical) || four_in_a_row?(horizontal) || four_in_a_row?(diagonal_up) || four_in_a_row?(diagonal_down) end def four_in_a_row?(array) !!array.chunk_while { |i,j| i == j }.find { |arr| arr.length >= 4 && arr[0] } end def column_full? @board[@row_index].length == 6 end def initialize_board 7.times.with_object([]) { |i, board| board << [] } end @seemaisms [email protected]
  6. class InvoiceCreator def initialize(user_id, invoice_date) @user_id = user_id @invoice_date =

    invoice_date end def create_invoice user_subscriptions = UserSubscription.where( user_id: @user_id ).select do |subcription| subscription.invoice_date == invoice_date end total_cost = user_subscriptions.sum do |user_subscription| if user_subscription.monthly_subscription? user_subscription.cost else user_subscription.cost /12 end end UserInvoice.create!(user_id: @user_id, amount: total_cost, date: @invoice_date) end end @seemaisms [email protected]
  7. class UserSubscriptionFetcher def fetch(user_id, invoice_date) UserSubscription.where(user_id: @user_id).select do |subcription| subscription.invoice_date

    == invoice_date end end end class UserSubscription def monthly_cost monthly_subscription? cost : cost /12 end end class InvoiceCreator def initialize(user_id, invoice_amount, invoice_date) @user_id = user_id @invoice_amount = invoice_amount @invoice_date = invoice_date end def create_invoice UserInvoice.create!(user_id: @user_id, amount: @invoice_amount, date: @invoice_date) end end @seemaisms [email protected]
  8. class Employee # ... def formatted_phone_number return '' if phone_number.blank?

    return "(#{phone[0..2]}) #{phone[3..5]}-#{phone[6..9]}" end end @seemaisms [email protected]
  9. class PayEmployee def self.call(employee) raise "Employee id #{employee.id} does not

    have a bank account" unless employee.bank_account raise "Company id #{company.id} does not have a bank account" unless company.bank_account payment = PaymentCreator.new(employee: employee).create_payment DebitCompanyForPayment.call(payment, employee.company) end end @seemaisms [email protected]
  10. context 'when the person lives in Tennessee' do context 'and

    also works there' do it 'includes taxes for Tennessee' do end end context 'when they work in a different state' do it 'includes taxes for that state also' do end end end @seemaisms [email protected]
  11. class User def full_name [ first_name, middle_initial, last_name].compact.join(' ') end

    end # in the test user = instance_double(User, first_name: 'Cookie', middle_initial: nil, last_name: 'Monster') @seemaisms [email protected]
  12. describe('user invoice callbacks') do it 'sends an email after the

    invoice is created' do expect(UserMailer).to receive :user_invoice_email UserInvoice.create end end @seemaisms [email protected]
  13. describe('user invoice callbacks') do it 'sends an email after the

    invoice is created' do expect(UserMailer).to receive :user_invoice_email UserInvoice.create end end This usually works. But, what if we only send emails on business days. @seemaisms [email protected]
  14. context ‘saving a file’ do let(:document) { create(:file, val: ‘test’)

    } subject { document.save_file! } it ‘writes to the right path’ do expect(File).to receive(:open).with("/tmp/documents/1/test") end @seemaisms [email protected]
  15. it ‘writes to the correct path’ do expect(File).to receive( :open

    ).with( “/tmp/documents/#{document.id}/artifact” ) end @seemaisms [email protected]
  16. class PhoneNumberFormatter def self.number_with_parentheses(phone_number) return '' if phone_number.blank? return "(#{phone[0..2]})

    #{phone[3..5]}-#{phone[6..9]}" end end class Employee def formatted_phone_number PhoneNumberFormatter.number_with_parentheses(phone) end end @seemaisms [email protected]
  17. class Employee def formatted_phone_number PhoneNumberFormatter.number_with_parentheses(phone) end end describe Employee do

    describe '#formatted_phone_number' do let(:phone_number) { '8001234567'} it 'returns the formatted version of the phone number' do expect(employee.formatted_phone_number).to eq('(800) 123-4567') end end end @seemaisms [email protected]
  18. describe Employee do describe '#formatted_phone_number' do it 'calls the formatter

    class' do expect(PhoneNumberFormatter).to receive(:number_with_parentheses). with(employee.phone) end end end @seemaisms [email protected]
  19. class Discount attr_reader :amount def initialize(amount) @amount = amount end

    end class DiscountCalculator def self.calculate(user_id) user_discounts = UserDiscount.where(user_id: user_id) user_discounts.sum { |ud| ud.discount.amount } end end @seemaisms [email protected]
  20. class Discount attr_reader :amount def initialize(amount) @amount = amount end

    end class DiscountCalculator def self.calculate(user_id) user_discounts = UserDiscount.where(user_id: user_id) user_discounts.sum { |ud| ud.discount.amount } end end Amount is sometimes the amount of the discount in cents but sometimes it is a percentage... @seemaisms [email protected]
  21. class PhoneNumberFormatter # this is used to format employee phone

    numbers, # user phone numbers, and admin phone numbers def self.number_with_parentheses(phone_number) return '' if phone_number.blank? return "(#{phone[0..2]}) #{phone[3..5]}-#{phone[6..9]}" end end @seemaisms [email protected]
  22. Any fool can write code that a computer can understand.

    Good programmers write code that humans can understand. — Refactoring: Improving the Design of Existing Code @seemaisms [email protected]