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

Objects, Testing, and Responsibility

Objects, Testing, and Responsibility

Talk from Laracon EU on August 31, 2013. Style issues due to reveal.js output.

Matt Machuga

August 31, 2013
Tweet

More Decks by Matt Machuga

Other Decks in Technology

Transcript

  1. ONLINE: MACHUGA IRC: machuga GitHub: machuga Twitter: @machuga I WEAR

    MANY HATS IN IRC "Have you checked the docs first?"
  2. THINK THROUGH LEARNING THINK THROUGH MATH HELP KIDS LEARN MATH

    SENIOR SOFTWARE DEVELOPER I HAVE THE BEST COWORKERS EVER!
  3. TESTING Correlation between good OOD and good tests Tests are

    good No, seriously. Tests are good. Stop hating.
  4. RESPONSIBILITY See also: Accountability Holding components accountable Giving objects explicit

    responsibilities 1:1 Object:Responsibility Ratio (when possible) Responsibilty to code Responsibilty to team Responsibilty to your future self
  5. Alan Kay Father of OOP "I thought of objects being

    like biological cells and/or individual computers on a network, only able to communicate with messages"
  6. OBJECT-ORIENTED PROGRAMMING Originated from Functional and Procedural Solution to code

    organization, data-hiding, reuse Solution to easier testing Solution to structure and protocols
  7. OOP: OBJECT ORIENTED PHP 16 years and 4 days ago:

    PHP codebase gets classes PHP 3 released in 1998 Associative Array ++
  8. OOP: OBJECT ORIENTED PHP PHP 3 & 4 CAPABILITIES Classes

    Objects Simple single inheritance Pass-by-value All public visibility
  9. OOP: OBJECT ORIENTED PHP PHP 5.0 - 5.2.X ENHANCEMENTS Pass-by-reference

    p u b l i c / p r i v a t e / p r o t e c t e d visibility Static methods/properties Class constants __construct() Destructors Abstract and Final classes Interfaces
  10. IT TOOK ABOUT 14 YEARS But we now have a

    very capable object model in PHP
  11. PROCEDURAL < ? p h p f u n c

    t i o n g e t _ d b ( ) { / * r e t u r n t h e d b c o n n e c i t o n * / } f u n c t i o n u s e r _ s h o w ( $ u s e r ) { / * A w e s o m e p r o c e d u r a l c o d e * / } f u n c t i o n u s e r _ f e t c h ( $ u s e r ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o d e * / f u n c t i o n u s e r _ d e l e t e ( $ u s e r ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o d e * / f u n c t i o n u s e r _ c r e a t e ( $ u s e r , $ d a t a ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o f u n c t i o n u s e r _ u p d a t e ( $ u s e r , $ d a t a ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o f u n c t i o n u s e r _ s t o r e _ d a t a ( $ u s e r , $ u s e r _ d a t a ) { i f ( u s e r _ f e t c h ( $ u s e r ) ) { r e t u r n u s e r _ u p d a t e ( $ u s e r , $ u s e r _ d a t a ) ; } e l s e { r e t u r n u s e r _ c r e a t e ( $ u s e r , $ u s e r _ d a t a ) ; }
  12. ABSTRACTED < p h p c l a s s

    U s e r e x t e n d s E l o q u e n t { / / A l l p r o v i d e d b y E l o q u e n t p u b l i c s t a t i c f u n c t i o n f i n d ( $ i d ) { } p u b l i c f u n c t i o n d e l e t e ( ) { } p u b l i c f u n c t i o n c r e a t e ( $ a t t r i b u t e s ) { } p u b l i c f u n c t i o n u p d a t e ( $ a t t r i b u t e s ) { } p u b l i c f u n c t i o n s a v e ( ) { } }
  13. ENCAPSULATION Keep data and behavior in a black box Use

    a public interface to interact with the black box Much like a function - data in, data out Prevents leaky abstractions
  14. ILLUMINATE\DATABASE\ELOQUENT\MODEL PROPERTIES 4 Public Instance/Class 19 Protected Instance/Class 0 Private

    Instance/Class METHODS 126 Public Instance/Class 25 Protected Instance/Class 0 Private Instance/Class
  15. INHERITANCE The double edged sword Allows classes to be extended

    from other classes Properties and methods can ascend the ancestry Saves a lot of code
  16. EXAMPLE - PLAIN CLASSES < ? p h p c

    l a s s R e c t a n g l e { p u b l i c f u n c t i o n _ _ c o n s t r u c t ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t C o o r d i n a t e s ( ) { } p u b l i c f u n c t i o n s e t C o o r d i n a t e s ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t X X ( ) { } p u b l i c f u n c t i o n g e t X Y ( ) { } p u b l i c f u n c t i o n g e t Y X ( ) { } p u b l i c f u n c t i o n g e t Y Y ( ) { } p u b l i c f u n c t i o n s e t X X ( $ c o o r d ) { } p u b l i c f u n c t i o n s e t X Y ( $ c o o r d ) { } p u b l i c f u n c t i o n s e t Y X ( $ c o o r d ) { } p u b l i c f u n c t i o n s e t Y Y ( $ c o o r d ) { }
  17. EXAMPLE - INHERITED < ? p h p c l

    a s s S q u a r e e x t e n d s R e c t a n g l e { } c l a s s D i a m o n d e x t e n d s R e c t a n g l e { } c l a s s R e c t a n g l e { p u b l i c f u n c t i o n _ _ c o n s t r u c t ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t C o o r d i n a t e s ( ) { } p u b l i c f u n c t i o n s e t C o o r d i n a t e s ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t X X ( ) { } p u b l i c f u n c t i o n g e t X Y ( ) { } p u b l i c f u n c t i o n g e t Y X ( ) { } p u b l i c f u n c t i o n g e t Y Y ( ) { } p u b l i c f u n c t i o n s e t X X ( $ c o o r d ) { }
  18. POLYMORPHISM Probably the best feature of OOP Any object may

    be used if it implements expected method/property Allows code branching without if/else logic PHP is a duck typed language - "If it walks like a duck" PHP also allows type hinting - "You will be a duck and you will like it!"
  19. EXAMPLE < p h p c l a s s

    B l o g P o s t W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s G a l l e r y W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s P o l l W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } }
  20. EXAMPLE W/ TYPE HINTING < p h p i n

    t e r f a c e W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s B l o g P o s t W i d g e t i m p l e m e n t s W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s G a l l e r y W i d g e t i m p l e m e n t s W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s P o l l W i d g e t i m p l e m e n t s W i d g e t
  21. DESIGN PATTERNS Finding common patterns in code and making it

    reusable Take advantage of OO constructs
  22. CODE REUSE AND EXTENSIBILITY Proper abstraction leads to reusable code

    Fluent Class in Laravel 3 as an example (not the DB one) Validators in Laravel Drivers
  23. LATE-STATIC BINDING s e l f never worked like it

    should've s t a t i c is what s e l f wanted to be s e l f will call the class the method was defined on, not the subclass you likely expecting s t a t i c however will
  24. EXAMPLE < p h p c l a s s

    A { p u b l i c f u n c t i o n s a d f a c e ( ) { r e t u r n n e w s e l f ( ) ; } p u b l i c f u n c t i o n h a p p y f a c e ( ) { r e t u r n n e w s t a t i c ( ) ; } } c l a s s B e x t e n d s A { } $ b = n e w B ( ) ; $ b - > s a d f a c e ( ) ; / / A o b j e c t
  25. TRAITS Traits allow for methods/properties to be added to a

    class at compile-time Not quite mixins, but close In a sense, allows for multiple inheritance This scares people Not always the right solution, but often suited Another great form of reusable abstraction
  26. EXAMPLE < p h p t r a i t

    B a r { p r o t e c t e d $ b a z ; p u b l i c f u n c t i o n b a z ( ) { r e t u r n $ t h i s - > b a z ; } } c l a s s F o o { u s e B a r ; p u b l i c f u n c t i o n s e t B a z ( $ b a z ) {
  27. TELL, DON'T ASK Tell your objects what you want them

    to do Don't ask them data about themselves. Remember: Black box
  28. COMPOSITION OVER INHERITANCE Composing two or more objects together The

    sum is greater than the parts Provides more flexibility Not always the right solution, but often the better suited More code to compose (usually) "Does X belong on this object?"
  29. COMPOSITION WITH TRAITS SOME PEOPLE REALLY HATE TRAITS Traits allow

    for methods/properties to be added to a class at compile-time Not quite mixins, but close In a sense, allows for multiple inheritance This scares people Not always the right solution, but often the better suited Another great form of reusable abstraction
  30. TDD SERVES MANY PURPOSES Guiding you to make well abstracted

    solutions Help you write the least code possible Ensure your code works Ensure your code works as it is intended Ensure tests become executable documentation for your code and acceptance criteria
  31. BASE TESTS OFF ACCEPTANCE CRITERIA Stakeholders want their features You

    want the features to work You want to guarantee your unit tests come together
  32. TDD IS NOT THE ONLY WAY Tests don't need to

    drive or guide your code Testing after is perfectly reasonable BUT ALWAYS LISTEN TO YOUR TESTS
  33. LISTENING TO TESTS Tests will let you know if somethign

    smells funny A class that does too many things is hard to test A test with too many dependencies is hard to test A test with too many mocks is hard to mantain A test that is too difficult is easy to abandon
  34. EXAMPLE - AUTHORITY < p h p p r o

    t e c t e d $ d i s p a t c h e r ; p u b l i c f u n c t i o n _ _ c o n s t r u c t ( $ c u r r e n t U s e r , $ d i s p a t c h e r = n u l l ) { $ t h i s - > r u l e s = n e w R u l e R e p o s i t o r y ; $ t h i s - > s e t D i s p a t c h e r ( $ d i s p a t c h e r ) ; $ t h i s - > s e t C u r r e n t U s e r ( $ c u r r e n t U s e r ) ; $ t h i s - > d i s p a t c h ( ' a u t h o r i t y . i n i t i a l i z e d ' , a r r a y ( ' u s e r ' = > $ t h i s - > g e t C u r r e n t U s e r ( ) , ) ) ; } p u b l i c f u n c t i o n d i s p a t c h ( $ e v e n t N a m e , $ p a y l o a d = a r r a y ( ) ) { i f ( $ t h i s - > d i s p a t c h e r ) { r e t u r n $ t h i s - > d i s p a t c h e r - > f i r e ( $ e v e n t N a m e , $ p a y l o a d ) ;
  35. EXAMPLE - AUTHORITY TESTS < p h p p u

    b l i c f u n c t i o n t e s t I n i t i a l i z e E v e n t ( ) { $ t e s t = n e w s t d C l a s s ; $ u s e r = n e w s t d C l a s s ; $ u s e r - > n a m e = ' T e s t e r ' ; $ t h i s - > d i s p a t c h e r - > l i s t e n ( ' a u t h o r i t y . i n i t i a l i z e d ' , f u n c t i o n ( $ p a y l o a d $ t e s t - > u s e r = $ p a y l o a d - > u s e r ; $ t e s t - > t i m e s t a m p = $ p a y l o a d - > t i m e s t a m p ; } ) ; $ a u t h o r i t y = n e w A u t h o r i t y ( $ u s e r , $ t h i s - > d i s p a t c h e r ) ; $ t h i s - > a s s e r t S a m e ( $ t e s t - > u s e r , $ u s e r ) ; $ t h i s - > a s s e r t I n s t a n c e O f ( ' D a t e T i m e ' , $ t e s t - > t i m e s t a m p ) ; }
  36. SOME THINGS ON TESTING You do not need a test

    for every method Sometimes you need more than one test for a method Mocking can fall short and lose sync. If you don't test everything, test areas of high churn Do not reach for AspectMock right away because something is hard Test your own code, not third party
  37. SOME MORE THINGS ON TESTING This is not a good

    test < p h p t e s t F o o ( ) { $ f o o = n e w F o o ( ) ; $ b a r = n e w B a r ( ) ; $ b a z = $ f o o - > d o S o m e t h i n g E p i c ( $ b a r ) ; i f ( i s _ a r r a y ( $ b a z ) a n d ! i s _ e m p t y ( $ b a z ) ) { $ t h i s - > a s s e r t T r u e ( t r u e ) ; } e l s e { $ t h i s - > a s s e r t F a l s e ( t r u e ) ; } }
  38. SOME MORE THINGS ON TESTING Nor this < p h

    p t e s t S o m e t h i n g ( ) { $ f o o = n e w F o o ( ) ; $ b a r = n e w B a r ( ) ; $ b a z = $ f o o - > d o S o m e t h i n g E p i c ( $ b a r ) ; / / B a z d o e s n ' t s e e m t o e v a l r i g h t , p a s s i n g f o r n o w / / @ T O D O : C o m e b a c k l a t e r $ t h i s - > a s s e r t T r u e ( t r u e ) ; }
  39. SOME MORE THINGS ON TESTING Nor this < p h

    p t e s t S t r i n g R e v e r s e ( ) { $ s t r = n e w A w e s o m e S t r i n g ( ) ; $ s t r i n g = ' H e l l o ' ; / / I m p l e m e n t a t i o n : r e t u r n s t r r e v ( $ s t r i n g ) $ r e v e r s e d = $ s t r - > r e v e r s e S t r i n g ( $ s t r i n g ) ; $ t h i s - > a s s e r t E q u a l s ( s t r r e v ( $ s t r i n g ) , $ r e v e r s e d ) ; }
  40. SOME MORE THINGS ON TESTING Nor this...I don't even... <

    p h p t e s t W e i r d F e a t u r e ( ) { / / 2 + 2 s h o u l d b e 4 i f ( 2 + 2 = = 3 ) { $ t h i s - > a s s e r t T r u e ( t r u e ) ; } e l s e { $ t h i s - > a s s e r t T r u e ( f a l s e ) ; } }
  41. RESPONSIBILITY: OBJECTS Give your objects a task Do not overwork

    your objects Give your objects some proper tests Like profiling and logging, objects can help with accountability
  42. RESPONSIBILITY: YOU You have a responsibility to yourself You have

    a responsibility to your team You have a responsibility to your consumers You have a responsibility to your future self Become responsible and be accountable for your code