How to Write Pleasant Code

How to Write Pleasant Code

[RubyConf 2019 - Roman Kofman]

As we grow from beginner to intermediate developers, we tend to learn tools and Best Practices for writing good code. But. The more we learn, the more contradictions show up -- and the murkier it gets to find the right answers. Senior developers sometimes chime in with "it depends!". Which -- while being technically accurate, is also completely unhelpful. What does it depend on? How do we reconcile Best Practices when they conflict with each other? Who is "good" code actually good for? Is perfectly clean code even possible?

We'll learn to find the answers to all of these questions by exploring the discipline of Design (think fancy chairs in museum); and stealing from it shamelessly.

A8461a517a89e1e2711883e1b51b0346?s=128

Roman Kofman

November 12, 2019
Tweet

Transcript

  1. 5.

    For me the purpose of life is partly to have

    joy. … So Ruby is designed to make programmers happy. Yukihiro Matsumoto @rkofman
  2. 10.
  3. 12.

    Code Design Principles • DRY - Don’t repeat yourself •

    High Cohesion / Low Coupling • SOLID @rkofman
  4. 13.

    Code Design Principles • DRY - Don’t repeat yourself •

    High Cohesion / Low Coupling • SOLID • Single Responsibility • Open / Closed • Liskov Substitution • Interface Segregation • Dependency Inversion @rkofman
  5. 14.
  6. 15.

    Code Design Principles • YAGNI - Ya aren’t gonna need

    it • Wrong Abstraction vs Duplication • Composition over Inheritance @rkofman
  7. 17.

    get '/employee/:id' do |id| employee = Employee.find id EmployeePresenter.new(employee).serialize end

    get '/employees' do employees = Employee.find_all employees.map do |employee| EmployeePresenter.new(employee).serialize end.to_s end @rkofman
  8. 18.

    class EmployeePresenter def initialize employee @e = employee end def

    serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.family_name}" end end @rkofman
  9. 21.

    class EmployeePresenter def initialize employee @e = employee end def

    serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.family_name}" end end @rkofman
  10. 22.

    class EmployeePresenter def initialize employee @e = employee @job =

    Job.find employee.job_id end def serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary}, job: #{@job.title} \}} end def full_name "#{@e.given_name} #{@e.family_name}" end end @rkofman
  11. 23.

    get '/employee/:id' do |id| employee = Employee.find id EmployeePresenter.serialize employee

    end get '/employees' do employees = Employee.find_all employees.map do |employee| EmployeePresenter.serialize employee end.to_s end @rkofman
  12. 27.

    class EmployeePresenter def initialize employee @e = employee @job =

    Job.find employee.job_id end def serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary}, job: #{@job.title} \}} end def full_name "#{@e.given_name} #{@e.family_name}" end end @rkofman
  13. 28.

    class EmployeePresenter def initialize employee, job @e = employee end

    def serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary}, job: #{@job.title} \}} end def full_name "#{@e.given_name} #{@e.family_name}" end end @rkofman
  14. 30.

    class EmployeePresenter def initialize employee @e = employee end def

    serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.f... end end class EmployeePresenter def initialize employee @e = employee end def serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.fam end end @rkofman
  15. 31.

    class EmployeePresenter def initialize employee @e = employee end def

    serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.f... end end class EmployeeListPresenter def initialize employee @e = employee end def serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.fam end end @rkofman
  16. 32.
  17. 34.

    def fibonacci n if n == 1 || n ==

    2 1 else fibonacci(n-1) + fibonacci(n-2) end end def fibonacci n second_last = 1 (1..n-2).inject(1) do |last, i| current = second_last + last second_last = last current end end Which is better? @rkofman
  18. 37.

    We need to focus on humans, on how humans care

    about doing programming. — Matz @rkofman
  19. 41.
  20. 51.

    class EmployeePresenter def initialize employee @e = employee end def

    serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.f... end end class EmployeePresenter def initialize employee @e = employee end def serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.fam end end @rkofman
  21. 52.

    class EmployeePresenter def initialize employee @e = employee end def

    serialize employee %{\{ full_name: #{full_name}, salary: #{@e.salary} \}} end def full_name "#{@e.given_name} #{@e.family_name}" end end @rkofman
  22. 54.

    get '/employees' do employees = Employee.find_all without_db do # throws

    errors if DB queries are attempted employees.map do |employee| EmployeePresenter.new(employee).serialize end.to_s end end @rkofman
  23. 55.

    Inspiration + Research Code Quality • Sarah Mei — Livable

    Code (RailsConf 2018) • Joe Mastey — Bringing UX to Your Code (RailsConf 2015) • Sandi Metz — Practical Object-Oriented Design in Ruby • Martin Fowler — Refactoring • Jim Weirich - Connascence Examined @rkofman
  24. 56.

    Inspiration + Research Design • Steve Krug — Don’t Make

    Me Think • Robin Williams — Non-Designer’s Design Book • Don Norman — Design of Everyday Things • Webitects — (Where I first learned about Design + Contextual Research) @rkofman