Stick to the rules

Ce277a152d715dabd06058e0ef502137?s=47 Adam Nowak
September 25, 2014

Stick to the rules

I talk about a few rules I tend to follow on a daily basis when I work with the code. I also talk a lot about adding abstraction layers everywhere.

Ce277a152d715dabd06058e0ef502137?s=128

Adam Nowak

September 25, 2014
Tweet

Transcript

  1. STICK TO THE RULES ADAM NOWAK / @LUBIENIEBIESKI @NETGURU

  2. WHAT RULES?! spoiler alert: this presentation will be about my

    code-related rules, most of them relatead to stuff I do working day to day with Ruby on Rails
  3. DON'T BE AFFRAID TO INTERRUPT AND DISCUSS / ASK QUESTIONS

  4. LOTS OF THE PRESENTED IDEAS ARE FROM THE IDEAL WORLD

    HE HE.
  5. NO IMAGES :(

  6. SOME CODE EXAMPLES YAY!

  7. WHY RULES?

  8. I'M LAZY. BUT I NEED TO GET THINGS DONE.

  9. IT'S GOOD TO STICK TO SOMETHING

  10. IT'S EASIER TO MAKE DECISIONS (OR EVEN NOT TO HAVE

    TO MAKE ONES)
  11. WE HAVE OUR WAY AT NETGURU - RULES ARE GOOD!

  12. SANDI METZ' RULES

  13. CLASSES SHOULD BE NO LONGER THAN ONE HUNDRED LINES OF

    CODE.
  14. METHODS SHOULD BE NO LONGER THAN FIVE LINES OF CODE.

  15. PASS NO MORE THAN FOUR PARAMETERS INTO A METHOD. HASH

    OPTIONS ARE PARAMETERS.
  16. CONTROLLERS SHOULD INSTANTIATE ONLY ONE OBJECT.

  17. CHECK A FOLLOW UP IN THIS POST http://robots.thoughtbot.com/sandi-metz-rules-for-developers

  18. A FEW GENERAL RULES

  19. DON'T REFACTOR TOO EARLY YOU MIGHT GET UNWANTED RESULTS

  20. RESPECT CODE STYLE GUIDES IF YOU'RE UNSURE HOW TO DO

    SOMETHING... JUST STICK TO THE RULES PROPOSED BY THE COMMUNITY https://github.com/bbatsov/ruby-style-guide
  21. TRY TO KEEP YOUR WORK/CODE/FOCUS SCOPE AS SMALL AS POSSIBLE

  22. THINK ABOUT COMMUNICATION

  23. METHOD NAMES RETURNING BOOL VALUES use ? sign / /

    s o m e _ v i e w . h a m l % h 1 = b o o k . p e r m i s s i o n s . f o r _ u s e r ( c u r r e n t _ u s e r ) = = ' r e a d ' vs # b o o k . r b d e f r e a d a b l e ? # s o m e c o d e r e t u r n i n g b o o l v a l u e t r u e e n d # b o o k . r e a d a b l e ? you should be able to read code like a newspaper
  24. ASK EXPLICITLY i f s o m e _ v

    a l u e . . . i f ! s o m e _ v a l u e . . . # u n l e s s s o m e _ v a l u e i f i t e m s vs i f s u m e _ v a l u e . p r e s e n t ? . . . i f s o m e _ v a l u e . n i l ? i f i t e m s . a n y ? all if statements should operate on boolean (t r u e /f a l s e ) values p r e s e n t ? n i l ? a n y ? a l l ? e x i s t s ? b l a n k ? e m p t y ?
  25. BANG BANG BANG! c l a s s T h

    i n g # i t ' s f o r m a t t e d b a d l y b e c a u s e i t w a s h a r d t o f i t i t h e r e d e f b r e a k ! @ b r o k e n = t r u e ; s e l f e n d d e f b r o k e n ? @ b r o k e n | | f a l s e e n d e n d t h i n g = T h i n g . n e w # > T h i n g : 0 x 0 0 7 f d b 6 c a e 0 a 2 0 t h i n g . b r o k e n ? # > f a l s e t h i n g . b r e a k ! # > T h i n g : 0 x 0 0 7 f d b 6 c a e 0 a 2 0 @ b r o k e n = t r u e t h i n g . b r o k e n ? # > t r u e CORE-LIB EXAMPLES WITH ! EQUIVALENTS: d o w n c a s e , u p c a s e , m e r g e , r e j e c t , etc.
  26. CONTEXT

  27. DIFFERENT RESPONSIBILITIES c l a s s P o s

    t h a s _ m a n y : c o m m e n t s e n d vs c l a s s A d m i n : : P o s t v a l i d a t e s : t i t l e , p r e s e n c e : t r u e e n d same object in different contexts has a different meaning
  28. NAMING VARIABLES... ... IS HARD! BUT IMPORTANT!

  29. NAME VARIABLES WITH REGARDS TO CONTEXT

  30. c l a s s R a c e R

    e s u l t d e f i n i t i a l i z e ( u s e r 1 , u s e r 2 ) . . . e n d e n d vs c l a s s R a c e R e s u l t d e f i n i t i a l i z e ( w i n n e r , r u n n e r u p ) . . . e n d e n d R a c e R e s u l t . n e w ( b i k e r _ j o h n , b i k e r _ s a m ) R a c e R e s u l t . n e w ( h o n d a _ c a r , b m w _ c a r )
  31. NAME OBJECTS SO SOMEONE ELSE IS ABLE TO UNDERSTAND ITS

    MEANING c o l l e c t i o n . e a c h d o | i t m | i t m . d e l ! e n d vs c a r t _ i t e m s . e a c h d o | i t e m | i t e m . b u y ! e n d
  32. TRY TO AVOID TOO GENERAL NAMING FOR OBJECT HOLDERS (CONTAINERS)

    e.g. c o n t a i n e r , a r r a y , h a s h - just name it after items it contains
  33. FEATURE FLAGS use f f _ * for naming features

    it's easy to find
  34. DEPENDENCIES

  35. PASS ALL THE ITEMS REQUIRED BY PARTIAL - # a

    p p / v i e w s / u s e r s / s o m e / n e s t e d / c o n t e x t / _ u s e r _ i n f o . h a m l = f r i e n d . n a m e vs - # a p p / v i e w s / f r i e n d s / s h o w . h a m l . . . = r e n d e r ' u s e r _ i n f o ' , u s e r : f r i e n d . . .
  36. DATA MIGRATIONS

  37. LOGALLTHETHINGS! c l a s s U p d a

    t e U s e r s A d d r e s s e s d e f u p s a y " N u m b e r o f u s e r s t o u p d a t e : # { U s e r . c o u n t } " s a y _ w i t h _ t i m e ' U p d a t i n g u s e r s a d d r e s s e s . . . ' d o . . . i f u s e r _ u p d a t e . f a i l e d ? s a y " U s e r # # { u s e r _ u p d a t e . u s e r _ i d } r e f u s e d t o b e u p d a t e d " e n d . . . e n d e n d e n d = = 2 0 1 4 1 0 0 9 0 9 4 2 1 4 U p d a t e U s e r s A d d r e s s e s s : m i g r a t i n g = = = = = = = = = = = = = - - N u m b e r o f u s e r s t o u p d a t e : 4 1 3 - - U p d a t i n g u s e r s a d d r e s s e s . . . - - U s e r # 6 6 6 r e f u s e d t o b e u p d a t e d - > 1 . 3 3 7 s
  38. AUDIT STATE PRE AND POST EXECUTION AND CHECK THE RESULTS

  39. MAKE IT RE-RUNNABLE AND DON'T BE STRESSED WHEN MIGRATION FAILS

  40. DON'T DEPEND ON AR RELATIONS

  41. REMEMBER ABOUT ROLLBACK MIGRATION

  42. GOOD APPROACH b i n / r a k e

    d b : m i g r a t e d b : r o l l b a c k & & b i n / r a k e d b : m i g r a t e http://robots.thoughtbot.com/workflows-for-writing- migrations-with-rollbacks-in-mind
  43. READ MORE: http://codecrate.com/2014/09/using-rails-migrations-to- manipulate-data.html http://railsguides.net/change-data-in-migrations-like-a-boss/ http://guides.rubyonrails.org/migrations.html#using-models- in-your-migrations

  44. WRAP THE DATA

  45. USE VIEW OBJECTS

  46. ... OR USE DECORATORS https://github.com/drapergem/draper

  47. ... OR USE BOTH

  48. View Object c l a s s S h o

    p p i n g C a r t V i e w a t t r _ a c c e s s o r : i t e m s d e f i n i t i a l i z e ( i t e m s ) s e l f . i t e m s = i t e m s e n d d e f t o t a l " # { i t e m s . s u m ( : p r i c e ) } R u b i e s " e n d d e f p o p u l a r _ i t e m s i t e m s . s e l e c t { | i | i . p o p u l a r ? } e n d e n d
  49. Decorator c l a s s C a r t

    I t e m D e c o r a t o r < D r a p e r : : D e c o r a t o r d e f s h o r t _ t i t l e o b j e c t . t i t l e . t r u n c a t e _ w o r d s ( 5 ) e n d d e f l i _ c s s _ c l a s s ' p o p u l a r ' i f p o p u l a r ? e n d e n d
  50. Template (view) % h 1 S h o p p

    i n g C a r t % u l - c a r t . i t e m s . e a c h d o | i t e m | % l i { c l a s s : i t e m . l i _ c s s _ c l a s s } = i t e m . s h o r t _ t i t l e = " # { c a r t . p o p u l a r _ i t e m s . c o u n t } o f y o u r i t e m s a r e v e r y p o p u l a r " e n d
  51. don't use models directly - decorate them if you have

    complex a logic - create an object wrapping all the data you need on a page it's good to have one object per page (it may contain other decorated objects) no need to use nested data (p o s t . a u t h o r . a d d r e s s . c i t y ) - structure your wrapping object as you need it in the template
  52. no more `@` in controllers! EXPOSE THE DATA CHECK HTTP://DECENTEXPOSURE.INFO/

  53. COMPARISON (1) # a p p / c o n

    t r o l l e r s / u s e r s _ c o n t r o l l e r . r b c l a s s U s e r s C o n t r o l l e r d e f i n d e x @ u s e r s = U s e r . a l l e n d e n d and view % h 1 U s e r s : = @ u s e r s . c o u n t
  54. COMPARISON (2) # a p p / c o n

    t r o l l e r s / u s e r s _ c o n t r o l l e r . r b c l a s s U s e r s C o n t r o l l e r h e l p e r _ m e t h o d : u s e r s d e f i n d e x ; e n d p r i v a t e d e f u s e r s U s e r . a l l e n d e n d and view % h 1 U s e r s : = u s e r s . c o u n t
  55. COMPARISON (3) # a p p / c o n

    t r o l l e r s / u s e r s _ c o n t r o l l e r . r b c l a s s U s e r s C o n t r o l l e r e x p o s e ( : u s e r s ) # e x p o s e ( : u s e r s ) { U s e r . a l l } d e f i n d e x ; e n d e n d and view % h 1 U s e r s : = u s e r s . c o u n t
  56. EXTRACT DATA GATHERING USE REPOSITIORIES

  57. SAMPLE REPOSITORY c l a s s I t e

    m R e p o s i t o r y a t t r _ a c c e s s o r : u s e r d e f i n i t i a l i z e ( u s e r ) s e l f . u s e r = u s e r e n d d e f a l l I t e m . w h e r e ( u s e r _ i d : u s e r . i d ) e n d d e f a c t i v e a l l . w h e r e ( a c t i v e : t r u e ) e n d e n d I t e m R e p o s i t o r y . n e w ( c u r r e n t _ u s e r ) . a c t i v e
  58. WHY? easy to test easy to use you can avoid

    scopes in model (good/bad) use with AR first, then easy to migrate to API-based solution
  59. RECENT IDEAS return collections as arrays, not A R :

    : R e l a t i o n focus on optimization encapsulated it repository no more n + 1 queries? no need for relations anymore?
  60. WANT MORE?

  61. USE SEARCH OBJECTS

  62. SAMPLE SEARCH OBJECT c l a s s I d

    e a S e a r c h s e a r c h _ o n I d e a s e a r c h e s : n a m e , : p o p u l a r d e f s e a r c h _ n a m e s e a r c h . w h e r e ( n a m e : n a m e ) e n d d e f s e a r c h _ p o p u l a r s e a r c h . w h e r e ( ' u s e r s _ c o u n t > 1 0 ' ) e n d e n d s e a r c h = I d e a S e a r c h . n e w ( p o p u l a r : t r u e ) s e a r c h . r e s u l t s
  63. CHECK OUT SEARCHLIGHT GEM https://github.com/nathanl/searchlight

  64. THIN MODELS VS THIN CONTROLLERS WHY NOT THIN... EVERYTHING?

  65. multiple layers = a lot more objects, but it will

    be much easier to maintain
  66. CONTROLLER IS THE PLACE WHERE YOU PUT YOUR DEPENDENCIES

  67. TYPICAL FLOW IN CONTROLLER JUST DISPLAYING THINGS get data (model)

    display data (model) VS get data (repository) display data (view object / decorator)
  68. MODEL # a r / p o s t .

    r b c l a s s P o s t < A c t i v e R e c o r d : : B a s e b e l o n g s _ t o : a u t h o r h a s _ m a n y : c o m m e n t s e n d REPOSITORY # r e p o s i t o r i e s / p o s t _ r e p o s i t o r y . r b c l a s s P o s t R e p o s i t o r y d e f a l l b a s e _ r e l a t i o n . o r d e r ( a u t h o r : : i d ) e n d p r i v a t e d e f b a s e _ r e l a t i o n P o s t . i n c l u d e s ( : c o m m e n t s , : a u t h o r ) e n d e n d
  69. VIEW OBJECT # v i e w _ o b

    j e c t s / p o s t _ v i e w . r b c l a s s P o s t V i e w a t t r _ a c c e s s o r : p o s t d e l e g a t e : t i t l e , : a u t h o r , t o : : p o s t d e f i n i t i a l i z e ( p o s t ) s e l f . p o s t = p o s t e n d d e f a u t h o r _ n a m e a u t h o r . n a m e e n d d e f a u t h o r _ a v a t a r g r a v a t a r ( a u t h o r . e m a i l ) e n d e n d
  70. CONTROLLER # c o n t r o l l

    e r s / p o s t s _ c o n t r o l l e r . r b c l a s s P o s t s C o n t r o l l e r d e f i n d e x @ p o s t s = d e c o r a t e d _ p o s t s e n d p r i v a t e d e f d e c o r a t e d _ p o s t s p o s t _ r e p o s i t o r y . a l l . m a p { | p | P o s t V i e w . n e w ( p o s t ) } e n d d e f p o s t _ r e p o s i t o r y P o s t R e p o s i t o r y . n e w e n d e n d
  71. VIEW # v i e w s / p o

    s t s / i n d e x . h a m l % h 1 A l l p o s t s % u l - @ p o s t s . e a c h d o | p o s t | % l i = p o s t . t i t l e b y = p o s t . a u t h o r _ n a m e
  72. USE SERVICES

  73. TYPICAL SERVICE c l a s s U s e

    r s : : C r e a t e a t t r _ a c c e s s o r : e m a i l , : u s e r _ m a i l e r d e f i n i t i a l i z e ( e m a i l : , u s e r _ m a i l e r = n i l ) s e l f . e m a i l = e m a i l s e l f . u s e r _ m a i l e r = u s e r _ m a i l e r | | U s e r M a i l e r . n e w e n d d e f c a l l u s e r = c r e a t e _ d b _ u s e r ( e m a i l ) s e n d _ i n t r o _ e m a i l ( u s e r ) u s e r e n d p r i v a t e d e f c r e a t e _ d b _ u s e r ( e m a i l ) ; e n d d e f s e n d _ i n t r o _ e m a i l ( u s e r ) u s e r _ m a i l e r . i n t r o ( u s e r ) . d e l i v e r e n d e n d
  74. RESPONSE OBJECTS c l a s s R e p

    o n s e : : S u c c e s s d e f s u c c e s s ? t r u e e n d e n d c l a s s R e p o n s e : : E r r o r d e f s u c c e s s ? f a l s e e n d e n d # . . . s e r v i c e c l a s s d e f c a l l . . . R e s p o n s e : : S u c c e s s . n e w e n d
  75. CONTROLLER GETS SMALLER c l a s s U s

    e r s C o n t r o l l e r d e f c r e a t e u s e r _ c r e a t i o n = U s e r s : : C r e a t e . n e w ( p a r a m s [ : u s e r ] ) . c a l l i f u s e r _ c r e a t i o n . s u c c e s s ? r e n d e r t e x t : ' O K ' e l s e r e n d e r t e x t : ' N O T O K ' , s t a t u s : : u n p r o c e s s a b l e _ e n t i t y e n d e n d e n d
  76. SERVICES: SUMMARY pass all the dependencies use only one public

    method `call` try them as special forces to do one job particulary well plurar namespace `Users::*` - avoid namespace clashes use response objects if needed read Pewniak's blogpost
  77. WHY THIS IS HARD?

  78. YOU HAVE TO WRITE MORE

  79. YOU HAVE TO TEST MORE

  80. YOU DON'T KNOW WHEN TO START

  81. 14 DEVELOPERS BEFORE YOU WERE TRYING THEIR APPROACH

  82. YOU HAVEN'T EXPERIENCED THE PAIN YET

  83. ... OR YOU HAVEN'T HEARD THE STORIES BY PEOPLE WHO

    HAVE
  84. TEST WISELY

  85. DON'T TEST PRIVATE METHODS they're about to change, those are

    only implementation details
  86. DON'T STUB TOO MUCH maybe use some dependency injections instead?

  87. FOCUS ON CONTEXTS

  88. ALWAYS HAVE YOUR GREENPATH COVERED WITH ACCEPTANCE TESTS remember: buisness

    is the most important thing (almost all the time)
  89. WHY IS IT BENEFICIAL?

  90. DISTRIBUTED RESPONSIBILITY

  91. TESTS ARE SIMPLER

  92. SMALLER SCOPES ALLOWS PEOPLE TO JUMP IN VERY QUICKLY

  93. THE END T.HANKS!