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

Stick to the rules

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.

Adam Nowak

September 25, 2014
Tweet

More Decks by Adam Nowak

Other Decks in Programming

Transcript

  1. 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
  2. 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
  3. 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
  4. 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 ?
  5. 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.
  6. 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
  7. 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 )
  8. 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
  9. 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
  10. 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 . . .
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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?
  23. 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
  24. TYPICAL FLOW IN CONTROLLER JUST DISPLAYING THINGS get data (model)

    display data (model) VS get data (repository) display data (view object / decorator)
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. ALWAYS HAVE YOUR GREENPATH COVERED WITH ACCEPTANCE TESTS remember: buisness

    is the most important thing (almost all the time)