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

Декларативное программирование и алгебраические типы данных в примерах для Django

Декларативное программирование и алгебраические типы данных в примерах для Django

Максим Аванов (Shopitize)

Рассказ о том, как базовые примитивы декларативного программирования одновременно избавляют от boilerplate-кода и контролируют согласованность логики гипотетического приложения на Django.

Moscow Python Meetup

April 28, 2014
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. Declarative Programming & Algebraic Data Types * Maxim Avanov maximavanov.com

    * from Django's perspective 19th Moscow Django Meetup
  2. Our Goal 1. «Outsource» boilerplate (i.e. concentrate on important). 2.

    Check as much as possible, and as soon as possible. 3. Component coherence.
  3. How vs. What d e f h a n d

    l e _ a r t i c l e _ f o r m ( r e q u e s t ) : i f r e q u e s t . m e t h o d = = ' P O S T ' : f o r m = A r t i c l e F o r m ( r e q u e s t . P O S T ) i f f o r m . i s _ v a l i d ( ) : s a v e _ a r t i c l e ( f o r m . c l e a n e d _ d a t a ) r e t u r n H t t p R e s p o n s e R e d i r e c t ( ' / s u c c e s s / ' ) e l s e : f o r m = A r t i c l e F o r m ( ) r e t u r n r e n d e r ( r e q u e s t , ' a r t i c l e _ f o r m . h t m l ' , { ' f o r m ' : f o r m } )
  4. How i f r e q u e s t

    . m e t h o d = = ' P O S T ' : f o r m = A r t i c l e F o r m ( r e q u e s t . P O S T ) i f f o r m . i s _ v a l i d ( ) : # . . . e l s e : # . . . What # c a s e 1 s a v e _ a r t i c l e ( f o r m . c l e a n e d _ d a t a ) r e t u r n H t t p R e s p o n s e R e d i r e c t ( ' / s u c c e s s / ' ) # c a s e 2 f o r m = A r t i c l e F o r m ( ) r e t u r n r e n d e r ( r e q u e s t , ' a r t i c l e _ f o r m . h t m l ' , { ' f o r m ' : f o r m } )
  5. A few things to worry about d e f h

    a n d l e _ a r t i c l e _ f o r m ( r e q u e s t ) : i f r e q u e s t . m e t h o d = = ' P O S T ' : f o r m = A r t i c l e F o r m ( r e q u e s t . P O S T ) i f f o r m . i s _ v a l i d ( ) : s a v e _ a r t i c l e ( f o r m . c l e a n e d _ d a t a ) r e t u r n H t t p R e s p o n s e R e d i r e c t ( ' / s u c c e s s / ' ) e l s e : f o r m = A r t i c l e F o r m ( ) r e t u r n r e n d e r ( r e q u e s t , ' a r t i c l e _ f o r m . h t m l ' , { ' f o r m ' : f o r m } ) «What» is obscured by «How» redundant details Single Responsibility principle is violated
  6. Tribute to Pyramid f r o m r h e

    t o r i c i m p o r t v i e w _ c o n f i g , v i e w _ d e f a u l t s @ v i e w _ d e f a u l t s ( r o u t e _ n a m e = ' a r t i c l e s ' , r e n d e r e r = ' a r t i c l e _ f o r m . h t m l ' ) c l a s s A r t i c l e s H a n d l e r ( o b j e c t ) : d e f _ _ i n i t _ _ ( s e l f , r e q u e s t ) : s e l f . r e q u e s t = r e q u e s t @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' G E T ' ) d e f a r t i c l e _ f o r m ( s e l f ) : f o r m = A r t i c l e F o r m ( ) r e t u r n { ' f o r m ' : f o r m } @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' , v a l i d a t e _ f o r m = A r t i c l e F o r m ) d e f s a v e _ a r t i c l e ( s e l f ) : s a v e _ a r t i c l e ( s e l f . r e q u e s t . f o r m . c l e a n e d _ d a t a ) r e t u r n H t t p R e s p o n s e R e d i r e c t ( ' / s u c c e s s / ' ) @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' ) d e f i n v a l i d _ a r t i c l e _ f o r m ( s e l f ) : r e t u r n { ' f o r m ' : s e l f . r e q u e s t . f o r m }
  7. What it actually means # W e h a v

    e a n A r t i c l e s H a n d l e r : A r t i c l e s H a n d l e r # I t r e n d e r s a t e m p l a t e : a r t i c l e _ f o r m . h t m l # A u s e r s h a l l b e a b l e t o a d d n e w e n t r i e s : a r t i c l e _ f o r m ( ) # I f w e s u b m i t v a l i d A r t i c l e F o r m : s a v e _ a r t i c l e ( ) # I f w e s u b m i t i n v a l i d A r t i c l e F o r m : i n v a l i d _ a r t i c l e _ f o r m ( ) c l a s s A r t i c l e s H a n d l e r ( o b j e c t ) : d e f _ _ i n i t _ _ ( s e l f , r e q u e s t ) : s e l f . r e q u e s t = r e q u e s t d e f a r t i c l e _ f o r m ( s e l f ) : f o r m = A r t i c l e F o r m ( ) r e t u r n { ' f o r m ' : f o r m } d e f s a v e _ a r t i c l e ( s e l f ) : s a v e _ a r t i c l e ( s e l f . r e q u e s t . f o r m . c l e a n e d _ d a t a ) r e t u r n H t t p R e s p o n s e R e d i r e c t ( ' / s u c c e s s / ' ) d e f i n v a l i d _ a r t i c l e _ f o r m ( s e l f ) : r e t u r n { ' f o r m ' : s e l f . r e q u e s t . f o r m }
  8. ...or in other words - - - v i e

    w : A r t i c l e s H a n d l e r G E T : a r t i c l e _ f o r m P O S T : - v a l i d a t e : a r t i c l e s . A r t i c l e F o r m v i e w : s a v e _ a r t i c l e - v i e w : i n v a l i d _ a r t i c l e _ f o r m c l a s s A r t i c l e s H a n d l e r ( o b j e c t ) : d e f _ _ i n i t _ _ ( s e l f , r e q u e s t ) : s e l f . r e q u e s t = r e q u e s t d e f a r t i c l e _ f o r m ( s e l f ) : f o r m = A r t i c l e F o r m ( ) r e t u r n { ' f o r m ' : f o r m } d e f s a v e _ a r t i c l e ( s e l f ) : s a v e _ a r t i c l e ( s e l f . r e q u e s t . f o r m . c l e a n e d _ d a t a ) r e t u r n H t t p R e s p o n s e R e d i r e c t ( ' / s u c c e s s / ' ) d e f i n v a l i d _ a r t i c l e _ f o r m ( s e l f ) : r e t u r n { ' f o r m ' : s e l f . r e q u e s t . f o r m }
  9. Different ways to do the same thing @ v i

    e w _ d e f a u l t s ( r o u t e _ n a m e = ' a u t h e n t i c a t i o n ' , r e n d e r e r = ' a u t h _ f o r m . h t m l ' ) c l a s s A u t h e n t i c a t i o n H a n d l e r ( o b j e c t ) : @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' , v a l i d a t e _ f o r m = E m a i l A u t h F o r m ) d e f a u t h _ w i t h _ e m a i l ( s e l f ) : # . . . @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' , v a l i d a t e _ f o r m = S M S A u t h F o r m ) d e f a u t h _ w i t h _ s m s ( s e l f ) : # . . . @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' , v a l i d a t e _ f o r m = L o g i n A u t h F o r m ) d e f a u t h _ w i t h _ l o g i n ( s e l f ) : # . . . @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' ) d e f o n _ i n v a l i d _ f o r m ( s e l f ) : # . . .
  10. API versioning c o n f i g . a

    d d _ r o u t e ( ' a p i . w o r k f l o w s ' , ' / a p i / w o r k f l o w s ' ) @ v i e w _ d e f a u l t s ( r o u t e _ n a m e = ' a p i . w o r k f l o w s ' , a p i _ v e r s i o n = ' < 2 . 0 ' ) c l a s s W o r k f l o w s A P I v 1 ( o b j e c t ) : # . . . @ v i e w _ d e f a u l t s ( r o u t e _ n a m e = ' a p i . w o r k f l o w s ' , a p i _ v e r s i o n = ' > = 2 . 0 ' ) c l a s s W o r k f l o w s A P I v 2 ( o b j e c t ) : # . . . @ v i e w _ d e f a u l t s ( r o u t e _ n a m e = ' a p i . w o r k f l o w s ' , r e n d e r e r = ' j s o n ' ) c l a s s W o r k f l o w s A P I ( o b j e c t ) : @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' , a p i _ v e r s i o n = ' < 2 . 0 ' ) d e f c r e a t e _ n e w _ w o r k f l o w _ v 1 ( s e l f ) : # . . . @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' P O S T ' , a p i _ v e r s i o n = ' > = 2 . 0 ' ) d e f c r e a t e _ n e w _ w o r k f l o w _ v 2 ( s e l f ) : # . . .
  11. OCaml ADT example Watch a «Caml Trading» talk by Yaron

    Minsky at http://youtu.be/hKcOkWzj0_s?t=31m6s
  12. OCaml ADT example t y p e o r d

    e r = { i d : i n t ; p r i c e : f l o a t ; s i z e : i n t ; } t y p e c a n c e l = { x i d : i n t ; } t y p e i n s t r u c t i o n = | O r d e r o f o r d e r | C a n c e l o f c a n c e l l e t f i l t e r _ b y _ o i d i n s t r u c t i o n s o i d = L i s t . f i l t e r i n s t r u c t i o n s ( f u n x - > m a t c h x w i t h | O r d e r o - > o . i d = o i d | C a n c e l c - > c . x i d = o i d )
  13. OCaml ADT example t y p e o r d

    e r = { i d : i n t ; p r i c e : f l o a t ; s i z e : i n t ; } t y p e c a n c e l = { x i d : i n t ; } t y p e c a n c e l _ r e p l a c e = { x r _ i d : i n t ; n e w _ p r i c e : f l o a t ; n e w _ s i z e : i n t ; } t y p e i n s t r u c t i o n = | O r d e r o f o r d e r | C a n c e l o f c a n c e l | C a n c e l _ r e p l a c e o f c a n c e l _ r e p l a c e l e t f i l t e r _ b y _ o i d i n s t r u c t i o n s o i d = L i s t . f i l t e r i n s t r u c t i o n s ( f u n x - > m a t c h x w i t h | O r d e r o - > o . i d = o i d | C a n c e l c - > c . x i d = o i d ) W a r n i n g P : T h i s p a t t e r n - m a t c h i n g i s n o t e x h a u s t i v e H e r e i s a n e x a m p l e o f a v a l u e t h a t i s n o t m a t c h e d . . .
  14. Python ADT example Models (product types) f r o m

    d j a n g o . d b i m p o r t m o d e l s c l a s s O r d e r ( m o d e l s . M o d e l ) : t i d = m o d e l s . I n t e g e r F i e l d ( ) p r i c e = m o d e l s . D e c i m a l F i e l d ( m a x _ d i g i t s = 1 6 , d e c i m a l _ p l a c e s = 4 ) s i z e = m o d e l s . I n t e g e r F i e l d ( ) c l a s s C a n c e l ( m o d e l s . M o d e l ) : x t i d = m o d e l s . I n t e g e r F i e l d ( ) c l a s s C a n c e l R e p l a c e ( m o d e l s . M o d e l ) : x r _ t i d = m o d e l s . I n t e g e r F i e l d ( ) n e w _ p r i c e = m o d e l s . D e c i m a l F i e l d ( m a x _ d i g i t s = 1 6 , d e c i m a l _ p l a c e s = 4 ) n e w _ s i z e = m o d e l s . I n t e g e r F i e l d ( )
  15. Python ADT example Smart Enums (union types) f r o

    m r h e t o r i c . a d t i m p o r t a d t f r o m . m o d e l s i m p o r t O r d e r , C a n c e l , C a n c e l R e p l a c e c l a s s I n s t r u c t i o n ( a d t ) : O R D E R = O r d e r C A N C E L = C a n c e l C A N C E L _ R E P L A C E = C a n c e l R e p l a c e
  16. Python ADT example Cases (match statement) f r o m

    . t y p e s i m p o r t I n s t r u c t i o n @ I n s t r u c t i o n . O R D E R ( ' f i l t e r _ b y _ o i d ' ) d e f f i l t e r _ o r d e r _ b y _ o i d ( o r d e r , o i d ) : r e t u r n o r d e r . t i d = = o i d @ I n s t r u c t i o n . C A N C E L ( ' f i l t e r _ b y _ o i d ' ) d e f f i l t e r _ c a n c e l _ b y _ o i d ( c a n c e l , o i d ) : r e t u r n c a n c e l . x t i d = = o i d @ I n s t r u c t i o n . C A N C E L _ R E P L A C E ( ' f i l t e r _ b y _ o i d ' ) d e f f i l t e r _ c a n c e l _ r e p l a c e _ b y _ o i d ( c r , o i d ) : r e t u r n c r . x r _ t i d = = o i d d e f f i l t e r _ b y _ o i d ( i n s t r u c t i o n s , o i d ) : r e t u r n l i s t ( f i l t e r ( l a m b d a i : I n s t r u c t i o n . m a t c h ( i ) [ ' f i l t e r _ b y _ o i d ' ] ( i , o i d ) , i n s t r u c t i o n s ) )
  17. Python ADT example Cases (2) f r o m .

    t y p e s i m p o r t I n s t r u c t i o n i n l i n e _ m a t c h e r = I n s t r u c t i o n . i n l i n e _ m a t c h ( O R D E R = ( l a m b d a o , o i d : o . t i d = = o i d ) , C A N C E L = ( l a m b d a c , o i d : c . x t i d = = o i d ) , C A N C E L _ R E P L A C E = ( l a m b d a c r , o i d : c r . x r _ t i d = = o i d ) ) d e f f i l t e r _ b y _ o i d _ a l t ( i n s t r u c t i o n s , o i d ) : r e t u r n l i s t ( f i l t e r ( l a m b d a i : i n l i n e _ m a t c h e r ( i ) ( i , o i d ) , i n s t r u c t i o n s ) )
  18. Use case Define ADT f r o m r h

    e t o r i c . a d t i m p o r t a d t c l a s s L a n g u a g e ( a d t ) : E N G L I S H = ' e n ' G E R M A N = ' d e '
  19. Use case Register Models f r o m d j

    a n g o . d b i m p o r t m o d e l s f r o m . t y p e s i m p o r t L a n g u a g e c l a s s I R e g i o n a l A r t i c l e ( m o d e l s . M o d e l ) : c l a s s M e t a : a b s t r a c t = T r u e t i t l e = m o d e l s . C h a r F i e l d ( m a x _ l e n g t h = 1 4 0 , d e f a u l t = ' ' ) t e x t = m o d e l s . T e x t F i e l d ( m a x _ l e n g t h = 6 5 5 3 6 , d e f a u l t = ' ' ) @ L a n g u a g e . E N G L I S H ( ' d b : a r t i c l e s ' ) c l a s s E n g l i s h A r t i c l e ( I R e g i o n a l A r t i c l e ) : p a s s @ L a n g u a g e . G E R M A N ( ' d b : a r t i c l e s ' ) c l a s s G e r m a n A r t i c l e ( I R e g i o n a l A r t i c l e ) : p a s s
  20. Use case Process requests f r o m r h

    e t o r i c . v i e w i m p o r t v i e w _ c o n f i g , v i e w _ d e f a u l t s f r o m . t y p e s i m p o r t L a n g u a g e @ v i e w _ d e f a u l t s ( r o u t e _ n a m e = ' a r t i c l e s . r e g i o n a l . i n d e x ' , r e n d e r e r = ' j s o n ' ) c l a s s A r t i c l e s H a n d l e r ( o b j e c t ) : d e f _ _ i n i t _ _ ( s e l f , r e q u e s t , l a n g u a g e ) : s e l f . r e q u e s t = r e q u e s t s e l f . l a n g u a g e = l a n g u a g e s e l f . l a n g u a g e _ s t r a t e g y = L a n g u a g e . m a t c h ( l a n g u a g e ) @ v i e w _ c o n f i g ( r e q u e s t _ m e t h o d = ' G E T ' ) d e f s h o w _ l o c a l _ e n t r i e s ( s e l f ) : r e t u r n { ' o k ' : T r u e }
  21. Consistency check Adding a new language c l a s

    s L a n g u a g e ( a d t ) : E N G L I S H = ' e n ' G E R M A N = ' d e ' S P A N I S H = ' e s ' C o n f i g u r a t i o n E r r o r : C a s e d b : a r t i c l e s o f < c l a s s ' p r o j e c t . a r t i c l e s . t y p e s . L a n g u a g e ' > i s n o t e x h a u s t i v e . H e r e i s t h e v a r i a n t t h a t i s n o t m a t c h e d : S P A N I S H # W e h a v e t o r e g i s t e r t h i s c a s e @ L a n g u a g e . S P A N I S H ( ' d b : a r t i c l e s ' ) c l a s s S p a n i s h A r t i c l e ( I R e g i o n a l A r t i c l e ) : p a s s
  22. Consistency check Using undefined variant f r o m r

    h e t o r i c . a d t i m p o r t a d t c l a s s L a n g u a g e ( a d t ) : E N G L I S H = ' e n ' G E R M A N = ' d e ' i n l i n e _ m a t c h e r = L a n g u a g e . i n l i n e _ m a t c h ( E N G L I S H = l a m b d a : E n g l i s h A r t i c l e . o b j e c t s . a l l ( ) , G E R M A N = l a m b d a : G e r m a n A r t i c l e . o b j e c t s . a l l ( ) , S P A N I S H = l a m b d a : S p a n i s h A r t i c l e . o b j e c t s . a l l ( ) ) P a t t e r n E r r o r : V a r i a n t S P A N I S H d o e s n o t b e l o n g t o t h e t y p e < c l a s s ' p r o j e c t . a r t i c l e s . t y p e s . L a n g u a g e ' >
  23. Consistency check Guard boundaries f r o m . t

    y p e s i m p o r t L a n g u a g e d e f i n c l u d e m e ( c o n f i g ) : R U L E S = { ' l a n g u a g e ' : L a n g u a g e } c o n f i g . a d d _ r o u t e ( ' a r t i c l e s . r e g i o n a l . i n d e x ' , ' / a r t i c l e s / { l a n g u a g e } ' , R U L E S ) / a r t i c l e s / { l a n g u a g e } = > ^ a r t i c l e s / ( ? P < l a n g u a g e > ( ? : d e | e n ) ) $ c l a s s L a n g u a g e ( a d t ) : E N G L I S H = ' e n ' G E R M A N = ' d e ' S P A N I S H = ' e s ' / a r t i c l e s / { l a n g u a g e } = > ^ a r t i c l e s / ( ? P < l a n g u a g e > ( ? : d e | e n | e s ) ) $
  24. Use case Strategy map c l a s s A

    r t i c l e s H a n d l e r ( o b j e c t ) : d e f _ _ i n i t _ _ ( s e l f , r e q u e s t , l a n g u a g e ) : s e l f . r e q u e s t = r e q u e s t s e l f . l a n g u a g e = l a n g u a g e s e l f . l a n g u a g e _ s t r a t e g y = L a n g u a g e . m a t c h ( l a n g u a g e ) G E T / a r t i c l e s / d e { ' d b : a r t i c l e s ' : < c l a s s ' p r o j e c t . a r t i c l e s . m o d e l s . G e r m a n A r t i c l e ' > } G E T / a r t i c l e s / e n { ' d b : a r t i c l e s ' : < c l a s s ' p r o j e c t . a r t i c l e s . m o d e l s . E n g l i s h A r t i c l e ' > }