Slide 1

Slide 1 text

Write your - by Bhavin Javia @bhavinjavia in Style www.mavenhive.in

Slide 2

Slide 2 text

Who this talk is NOT for ?

Slide 3

Slide 3 text

I am the only one !

Slide 4

Slide 4 text

Who this talk IS for ?

Slide 5

Slide 5 text

Dad ! Who’s ‘Ruby’ ?

Slide 6

Slide 6 text

Teams

Slide 7

Slide 7 text

Open Source Contributors

Slide 8

Slide 8 text

Style Matters

Slide 9

Slide 9 text

Why bother ?

Slide 10

Slide 10 text

Story

Slide 11

Slide 11 text

Rubo

Slide 12

Slide 12 text

• Fascinated by computers • Learnt programming in school/college • Knew a few languages - C, C++, Java • Loved Ruby • Joined a Startup as an Intern • Full of Ruby veterans • Felt right at home Story of Rubo

Slide 13

Slide 13 text

Ruby Rocks !

Slide 14

Slide 14 text

But,

Slide 15

Slide 15 text

As soon as he committed some code ...

Slide 16

Slide 16 text

WTF ? OMG ! #$%@ Caveman !

Slide 17

Slide 17 text

Oh, Where did I go wrong ?!

Slide 18

Slide 18 text

What was wrong ?

Slide 19

Slide 19 text

He lacked Style

Slide 20

Slide 20 text

Masters of Ruby Style http://www.flickr.com/photos/jakescruggs/4687409786/ http://vimeo.com/steveklabnik https://si0.twimg.com/profile_images/2931712744/95043c0f42f0700bdbd713635e942ac0.jpeg http://peepcode.com/blog/2011/my-avatar/circle1.jpg

Slide 21

Slide 21 text

• Java - Code Conventions for Java (by Oracle) • Python - Style Guide for Python Code (PEP 8) • PHP - Basic Coding Standard (PSR-1) Many languages have Coding Standards http://www.oracle.com/technetwork/java/codeconv-138413.html http://www.python.org/dev/peps/pep-0008/ http://www.php-fig.org/psr/1/

Slide 22

Slide 22 text

Why Ruby doesn’t ?

Slide 23

Slide 23 text

Many ways to do things ...

Slide 24

Slide 24 text

And all of them work !

Slide 25

Slide 25 text

Ruby Sucks !

Slide 26

Slide 26 text

We need a Style Guide

Slide 27

Slide 27 text

What is a Style Guide ?

Slide 28

Slide 28 text

What’s a Style Guide ? • Better way to write code • Better way to lay-out code • Right idioms to use and when • Simplicity and Elegance

Slide 29

Slide 29 text

Helps you decide ...

Slide 30

Slide 30 text

http://flic.kr/p/5n8Rrd what your code should look like ? this ...

Slide 31

Slide 31 text

http://flic.kr/p/voGgz or this ?

Slide 32

Slide 32 text

I’ve got my own Style

Slide 33

Slide 33 text

Why Style Guide ?

Slide 34

Slide 34 text

Why Style Guide ? • Functional correctness not enough • Visual consistency matters • Reduce cognitive friction • Avoid religious wars • Increase team productivity • Long term maintainability

Slide 35

Slide 35 text

Let the team own it

Slide 36

Slide 36 text

When no one owns the code, everyone owns the code !

Slide 37

Slide 37 text

http://flic.kr/p/6mHZfT code which lasts 1000s of years

Slide 38

Slide 38 text

Examples

Slide 39

Slide 39 text

Code Layout

Slide 40

Slide 40 text

“ Nearly everybody is convinced that every style but their own is ugly and unreadable. Leave out the "but their own" and they're probably right... - Jerry Coffin (on indentation)

Slide 41

Slide 41 text

# encoding: utf-8 https://help.github.com/articles/dealing-with-line-endings $ git config --global core.autocrlf input # Mac/Linux $ git config --global core.autocrlf true # Windows Use UTF-8 as the source file encoding Use Unix-style line endings

Slide 42

Slide 42 text

# bad - four spaces def some_method do_something end # good def some_method do_something end * No tabs please Two spaces per indent

Slide 43

Slide 43 text

# bad def too_much; something; something_else; end # okish def no_braces_method; body; end # okish def some_method() body end # good def some_method body end * Not applicable to empty methods e.g. # good def no_op; end Avoid single-line methods

Slide 44

Slide 44 text

# around operators, after commas, colons and semicolons, around `{` and before `}` sum = 1 + 2 a, b = 1, 2 1 > 2 ? true : false; puts 'Hi' [1, 2, 3].each { |e| puts e } * Not with exponent operator # bad e = M * c ** 2 # good e = M * c**2 Use spaces

Slide 45

Slide 45 text

Indent when as deep as case case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end kind = case year when 1850..1889 then 'Blues' when 1890..1909 then 'Ragtime' when 1910..1929 then 'New Orleans Jazz' when 1930..1939 then 'Swing' when 1940..1950 then 'Bebop' else 'Jazz' end

Slide 46

Slide 46 text

Avoid line continuation # bad result = 1 - \ 2 # bad result = 1 \ - 2

Slide 47

Slide 47 text

# bad one.two.three. four # good one.two.three .four Chain methods with .

Slide 48

Slide 48 text

Align multi-line params # starting point (line is too long) def send_mail(source) Mailer.deliver(to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source. text) end # bad (normal indent) def send_mail(source) Mailer.deliver( to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end

Slide 49

Slide 49 text

Align multi-line params # bad (double indent) def send_mail(source) Mailer.deliver( to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end # good def send_mail(source) Mailer.deliver(to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end

Slide 50

Slide 50 text

num = 1000000 num = 1_000_000 Which one is correct ?

Slide 51

Slide 51 text

num = 1000000 num = 1_000_000 Both ! Which one is better ?

Slide 52

Slide 52 text

Add underscores to large numeric literals # bad - how many 0s are there? num = 1000000 # good - much easier to parse num = 1_000_000

Slide 53

Slide 53 text

class Array # Calls to_param on all its elements and joins the result with # slashes. This is used by url_for in Action Pack. def to_param collect { |e| e.to_param }.join '/' end end Use RDoc and its conventions for API docs

Slide 54

Slide 54 text

Syntax

Slide 55

Slide 55 text

Use Iterators arr = [1, 2, 3] # bad for elem in arr do puts elem end # good arr.each { |elem| puts elem }

Slide 56

Slide 56 text

# bad result = if some_condition then something else something_else end # good result = some_condition ? something : something_else * for one line constructs Favor the ternary operator (?:) over if/then/else/end

Slide 57

Slide 57 text

# bad some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else # good if some_condition nested_condition ? nested_something : nested_something_else else something_else end Use one expression per branch in a ternary operator

Slide 58

Slide 58 text

# bad if some_condition do_something do_something_else end # good if some_condition do_something do_something_else end Always put the condition on the same line

Slide 59

Slide 59 text

Favor unless over if for negative conditions # bad do_something if !some_condition # bad do_something if not some_condition # good do_something unless some_condition # another good option some_condition || do_something

Slide 60

Slide 60 text

class Person attr_reader :name, :age # omitted end temperance = Person.new('Temperance', 30) temperance.name puts temperance.age x = Math.sin(y) array.delete(e) bowling.score.should == 0 Omit parentheses around parameters for methods that are part of internal DSL, keyword status, accessors

Slide 61

Slide 61 text

names = ['Bozhidar', 'Steve', 'Sarah'] # bad names.each do |name| puts name end # good names.each { |name| puts name } * Avoid using {...} for multi-line blocks Prefer {...} over do...end for single-line blocks

Slide 62

Slide 62 text

# bad def some_method(some_arr) return some_arr.size end # good def some_method(some_arr) some_arr.size end Avoid return where not required for flow of control

Slide 63

Slide 63 text

# bad def ready? if self.last_reviewed_at > self.last_updated_at self.worker.update(self.content, self.options) self.status = :in_progress end self.status == :verified end # good def ready? if last_reviewed_at > last_updated_at worker.update(content, options) self.status = :in_progress end status == :verified end * only required when calling a self write accessor Avoid self where not required

Slide 64

Slide 64 text

Naming

Slide 65

Slide 65 text

“ The only real difficulties in programming are cache invalidation and naming things. - Phil Karlton

Slide 66

Slide 66 text

Name identifiers in English # bad - variable name written in Bulgarian with latin characters zaplata = 1_000 # good salary = 1_000

Slide 67

Slide 67 text

Use CamelCase for classes and modules # bad class Someclass ... end class Some_Class ... end class SomeXml ... end # good class SomeClass ... end class SomeXML ... end * Keep acronyms like HTTP, RFC, XML uppercase

Slide 68

Slide 68 text

Use snake_case for symbols, methods and variables # bad :'some symbol' :SomeSymbol :someSymbol someVar = 5 def someMethod ... end def SomeMethod ... end # good :some_symbol some_var = 5 def some_method ... end

Slide 69

Slide 69 text

Use SCREAMING_SNAKE_CASE for other constants. # bad SomeConst = 5 # good SOME_CONST = 5

Slide 70

Slide 70 text

Predicate methods shouldshould end in a question mark ‘?’ # bad def available appointments.empty? end # good def available? appointments.empty? end * e.g. Array#empty?

Slide 71

Slide 71 text

Comments

Slide 72

Slide 72 text

“ Good code is its own best documentation ... - Steve McConnell “ Good code is like a good joke - it needs no explanation. - Russ Olsen

Slide 73

Slide 73 text

Avoid superfluous comments # bad counter += 1 # increments counter by one

Slide 74

Slide 74 text

Avoid writing comments to explain bad code

Slide 75

Slide 75 text

An outdated comment is worse than no comment at all !

Slide 76

Slide 76 text

DON’T do it !

Slide 77

Slide 77 text

Use Comment Annotations • Use TODO to note missing features • Use FIXME to note broken code • Use HACK to note code smells • Use OPTIMIZE to note inefficient code

Slide 78

Slide 78 text

One you’ve added annotations

Slide 79

Slide 79 text

DO do the TODO !

Slide 80

Slide 80 text

Classes & Modules

Slide 81

Slide 81 text

Use a consistent structure in your class definitions class Person # extend and include extend SomeModule include AnotherModule # constants SOME_CONSTANT = 20 # attribute macros attr_reader :name # other macros (if any) validates :name # public class methods are next in line def self.some_method end # followed by public instance methods def some_method end # protected/private methods end

Slide 82

Slide 82 text

Implement to_s on domain classes class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end def to_s "#{@first_name} #{@last_name}" end end

Slide 83

Slide 83 text

Use the attr family of functions to define trivial accessors # bad class Person def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end def first_name @first_name end def last_name @last_name end end # good class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end end

Slide 84

Slide 84 text

What if I don’t like these ‘rules’ ?

Slide 85

Slide 85 text

Rules are meant to be broken ! http://flic.kr/p/dKyXLP

Slide 86

Slide 86 text

http://flic.kr/p/7MdXLX These are just guidelines

Slide 87

Slide 87 text

Follow Style Guide consistently

Slide 88

Slide 88 text

But,

Slide 89

Slide 89 text

“ A Foolish Consistency is the Hobgoblin of Little Minds - Essays: First Series by Ralph Waldo Emerson

Slide 90

Slide 90 text

Consistency at what level ? • consistency with style guide - important • consistency with project - more important • consistency with module - most important • readability matters

Slide 91

Slide 91 text

https://twitter.com/AgileBorat/status/307791971991289856

Slide 92

Slide 92 text

When to break the rule ? • Applying the rule makes it less readable • To be consistent with surrounding code • Opportunity to clean up the mess

Slide 93

Slide 93 text

How to enforce these rules ?

Slide 94

Slide 94 text

• Make it a standard team practice • Select/Draft a style guide for project • Make it a must read for everyone • Use IDE support e.g. RubyMine inspections How to enforce these rules ?

Slide 95

Slide 95 text

• Use Style Checker tools • Integrate with CI • Use a live style guide - fork it, send PRs • Commit your IDE settings • Point out violations in context • Use Github inline commit notes How to enforce these rules ?

Slide 96

Slide 96 text

https://github.com/blog/622-inline-commit-notes

Slide 97

Slide 97 text

Tools

Slide 98

Slide 98 text

Rubocop https://github.com/bbatsov/rubocop

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

Demo

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

Like a Boss !

Slide 104

Slide 104 text

References • https://github.com/bbatsov/ruby-style-guide • https://github.com/styleguide/ruby • https://github.com/bbatsov/rails-style-guide Style Guides

Slide 105

Slide 105 text

References • https://github.com/bbatsov/rubocop • https://github.com/martinjandrews/roodi • https://github.com/troessner/reek Tools

Slide 106

Slide 106 text

Give it a shot

Slide 107

Slide 107 text

YMMV

Slide 108

Slide 108 text

Contribute your Style to the community

Slide 109

Slide 109 text

Thank You

Slide 110

Slide 110 text

Questions ? @bhavinjavia [email protected] www.mavenhive.in @mavenhive