Diese Präsentation wurde erfolgreich gemeldet.

Orthogonal Functional Architecture

14

Teilen

Wird geladen in …3
×
1 von 52
1 von 52

Orthogonal Functional Architecture

14

Teilen

Herunterladen, um offline zu lesen

Beschreibung

Well-architected libraries for functional programming are at once immensely beautiful and practical. They are simple but extraordinarily powerful, helping users solve their problems by snapping together Lego-like building blocks, each of which has just one purpose. Yet, there is a surprising dearth of material on how developers can construct their own well-architected functional code. Many functional programming tutorials talk discuss type safety and making illegal states unrepresentable, but few speak on the subject of good functional interface design.
In this presentation, John A. De Goes takes to the stage to discuss a nebulous and underrated tool in the arsenal of every functional programmer. Called *orthogonality*, this tool allows programmers to craft the building blocks of their functional code at "right angles", so so they can be reasoned about simply and composed predictably to solve complex problems. John introduces the concept of orthogonality, looking at its geometric and algebraic origins, presents a way to measure orthogonality, and then walks through a number of interface examples, comparing non-orthogonal designs with orthogonal ones.
By the end of the session, attendees should have a newfound appreciation for how important orthogonality is to constructing good functional interfaces, and they should develop the early stages of an intuition about how to slice up a complex problem into core, single-purpose, composable building blocks.

Transkript

  1. 1. Orthogonal Functional Architecture Lambda Squared - Knoxville, TN John A. De Goes — @jdegoes http://degoes.net
  2. 2. Introduction
  3. 3. The Dysfunctional Nightmare abandon all hope ye who enter
  4. 4. Procedural Code Ad hoc solutions constructed from large number of non-composable effects that are reasoned about non-locally.
  5. 5. The Functional Dream bliss awaits all ye who enter
  6. 6. Functional Code Principled solutions constructed from a small number of composable building blocks that are reasoned about locally.
  7. 7. Two Keys to Bliss Orthogonality + Composability
  8. 8. Two Keys to Bliss Composability makes functional code powerful, and orthogonality makes it beautiful* *i.e. modular and uncluttered by irrelevant details.
  9. 9. Two Keys to Bliss Composable, orthogonal bases tend to be powerful, but small and simple to reason about, permitting flexible, modular solutions to many problems.
  10. 10. Composability
  11. 11. Composability public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this Java Future composable?
  12. 12. Composability Composability measures the extent to which values can be combined with other values to produce like values
  13. 13. Composability 1 + 1 = 2 Two integers combine to yield another integer. 1 – 1 = 0 Integers are composable with respect to addition/subtraction.
  14. 14. Composability Non-Composable Composable
  15. 15. Composability public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this Java Future composable?
  16. 16. Orthogonality
  17. 17. Orthogonality public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this Java Future orthogonal?
  18. 18. Orthogonality Orthogonality measures the extent to which primitive operations on values have single, unique concerns
  19. 19. Orthogonality Addition moves right Addition/subtraction are orthogonal Subtraction moves left
  20. 20. Orthogonality A A + B B A Non-Orthogonal Orthogonal B
  21. 21. Orthogonality public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this orthogonal?
  22. 22. Orthogonality public interface Future<V> { boolean cancel( boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this orthogonal? Timeout Get Timeout + Get
  23. 23. Orthogonality The cardinal sin of non-orthogonality is the tangling of separate concerns, which infects the code base to destroy modularity.
  24. 24. Orthogonality
  25. 25. Process
  26. 26. Steps Toward Orthogonality 1. Make the system composable.
  27. 27. Steps Toward Orthogonality 2. Identify the primitive operations.
  28. 28. Steps Toward Orthogonality 3. Identify the unique concerns.
  29. 29. Steps Toward Orthogonality 4. Refactor the primitive operations until each has a unique concern.
  30. 30. Worked Examples
  31. 31. Worked Examples public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException,ExecutionException, TimeoutException; } Is this orthogonal?
  32. 32. Worked Examples The curse of non-orthogonality! // Would like to write: <A> Future<A> retryUntilSuccess(Future<A> future, Interval spacing) { // ??? } // Forced to write: A retryUntilSuccess(Future<A> future, Interval spacing, long timeout, TimeUnit unit) { // ... }
  33. 33. Worked Examples public interface Future<V> { Future<Tuple2<Future<V>, Function<Boolean, Future<Unit>>>> fork(); V unsafePerformGet() throws InterruptedException, ExecutionException; Future<V> timeout(long timeout, TimeUnit unit); } Future 2.0: Detangle ‘get’ and ‘timeout’
  34. 34. Worked Examples Is this orthogonal? static int compare( String str1, String str2, boolean nullIsLess)
  35. 35. Worked Examples Is this orthogonal? NullIsLess + Comparison NullIsLess Comparison static int compare( String str1, String str2, boolean nullIsLess)
  36. 36. Worked Examples The curse of non-orthogonality! List<String> myAlgorithm(List<String> list, boolean nullIsFirst) { // ... int c = compare(first, second, nullIsFirst); // ... }
  37. 37. enum Ordering { LT, EQ, GT } interface Ord<A> { Ordering compare(A l, A r); } Worked Examples 1. Define a unit of composition
  38. 38. class StringOrd extends Ord<String> { public Ordering compare(String l, String r) { // ... } } Worked Examples 2. Define one dimension (string comparison)
  39. 39. class NullIsLess<A> { private final Ord<A> ord; public NullIsLess(Ord<A> ord) { this.ord = ord; } public Ordering compare(A l, A r) { if (l == null) { if (r == null) return EQ; else return LT; } else if (r == null) return GT; else return ord.compare(l, r); } } Worked Examples 3. Define another dimension (null is first)
  40. 40. List<String> myAlgorithm(List<String> list, Ord<String> ord) { // ... Ordering c = ord.compare(first, second); // <- Beautiful!!! // ... } Ord<String> ord = new NullIsLess<String>(new StringOrd()); List<String> list2 = myAlgorithm(list, ord); Worked Examples 4. Compose orthogonal components
  41. 41. Worked Examples Is this orthogonal?* data MVar a putMVar :: MVar a -> a -> IO () takeMVar :: MVar a -> IO a *Thanks to Fabio the fabulous for this example.
  42. 42. Worked Examples Is this orthogonal? data MVar a putMVar :: MVar a -> a -> IO () takeMVar :: MVar a -> IO a Synchronization + Concurrency Synchronization Concurrency
  43. 43. Worked Examples data IORef a newtype Expect a = Expect a modify :: IORef a -> (a -> a) -> IO Bool data Promise a newPromise :: IO (Promise a, a -> IO ()) awaitPromise :: Promise a -> IO a Synchronization (IORef) Concurrency (Promise)
  44. 44. Worked Examples Is this orthogonal?* *A tiny part of Apache String Utils.
  45. 45. Worked Examples Is this orthogonal? ? ?
  46. 46. Worked Examples Is this orthogonal? data Parser a = Parser (String -> Either String (String, a)) char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a seq :: Parser a -> (a -> Parser b) -> Parser b pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b
  47. 47. Worked Examples Is this orthogonal?* data Parser a = Parser (String -> Either String (String, a)) char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a seq :: Parser a -> (a -> Parser b) -> Parser b pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b *Trick question — or is it?
  48. 48. Worked Examples Is this orthogonal? data Parser a = Parser (String -> ... char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a seq :: Parser a -> (a -> Parser b) -> Parser b pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b SequencingMapping Flattening
  49. 49. Worked Examples Is this orthogonal? data Parser a = Parser (String -> ... char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a join :: Parser (Parser a) -> Parser a pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b Mapping Flattening
  50. 50. Wrap
  51. 51. Summary 1. Functional code is composable and orthogonal, allowing a small set of principled building blocks to snap together to solve complex problems in a predictable, reasonable way. 2. Composability measures the combinability of values. 3. Orthogonality measures the singular focus of primitive operations. 4. Refactor to orthogonality to obtain modular clode, uncluttered by irrelevant details.
  52. 52. Thank You! Special thanks to Reid, Cameron, Emily, & the wonderful Knoxville FP community, and the generous sponsor ResultStack! John A. De Goes — @jdegoes http://degoes.net

Beschreibung

Well-architected libraries for functional programming are at once immensely beautiful and practical. They are simple but extraordinarily powerful, helping users solve their problems by snapping together Lego-like building blocks, each of which has just one purpose. Yet, there is a surprising dearth of material on how developers can construct their own well-architected functional code. Many functional programming tutorials talk discuss type safety and making illegal states unrepresentable, but few speak on the subject of good functional interface design.
In this presentation, John A. De Goes takes to the stage to discuss a nebulous and underrated tool in the arsenal of every functional programmer. Called *orthogonality*, this tool allows programmers to craft the building blocks of their functional code at "right angles", so so they can be reasoned about simply and composed predictably to solve complex problems. John introduces the concept of orthogonality, looking at its geometric and algebraic origins, presents a way to measure orthogonality, and then walks through a number of interface examples, comparing non-orthogonal designs with orthogonal ones.
By the end of the session, attendees should have a newfound appreciation for how important orthogonality is to constructing good functional interfaces, and they should develop the early stages of an intuition about how to slice up a complex problem into core, single-purpose, composable building blocks.

Transkript

  1. 1. Orthogonal Functional Architecture Lambda Squared - Knoxville, TN John A. De Goes — @jdegoes http://degoes.net
  2. 2. Introduction
  3. 3. The Dysfunctional Nightmare abandon all hope ye who enter
  4. 4. Procedural Code Ad hoc solutions constructed from large number of non-composable effects that are reasoned about non-locally.
  5. 5. The Functional Dream bliss awaits all ye who enter
  6. 6. Functional Code Principled solutions constructed from a small number of composable building blocks that are reasoned about locally.
  7. 7. Two Keys to Bliss Orthogonality + Composability
  8. 8. Two Keys to Bliss Composability makes functional code powerful, and orthogonality makes it beautiful* *i.e. modular and uncluttered by irrelevant details.
  9. 9. Two Keys to Bliss Composable, orthogonal bases tend to be powerful, but small and simple to reason about, permitting flexible, modular solutions to many problems.
  10. 10. Composability
  11. 11. Composability public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this Java Future composable?
  12. 12. Composability Composability measures the extent to which values can be combined with other values to produce like values
  13. 13. Composability 1 + 1 = 2 Two integers combine to yield another integer. 1 – 1 = 0 Integers are composable with respect to addition/subtraction.
  14. 14. Composability Non-Composable Composable
  15. 15. Composability public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this Java Future composable?
  16. 16. Orthogonality
  17. 17. Orthogonality public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this Java Future orthogonal?
  18. 18. Orthogonality Orthogonality measures the extent to which primitive operations on values have single, unique concerns
  19. 19. Orthogonality Addition moves right Addition/subtraction are orthogonal Subtraction moves left
  20. 20. Orthogonality A A + B B A Non-Orthogonal Orthogonal B
  21. 21. Orthogonality public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this orthogonal?
  22. 22. Orthogonality public interface Future<V> { boolean cancel( boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Is this orthogonal? Timeout Get Timeout + Get
  23. 23. Orthogonality The cardinal sin of non-orthogonality is the tangling of separate concerns, which infects the code base to destroy modularity.
  24. 24. Orthogonality
  25. 25. Process
  26. 26. Steps Toward Orthogonality 1. Make the system composable.
  27. 27. Steps Toward Orthogonality 2. Identify the primitive operations.
  28. 28. Steps Toward Orthogonality 3. Identify the unique concerns.
  29. 29. Steps Toward Orthogonality 4. Refactor the primitive operations until each has a unique concern.
  30. 30. Worked Examples
  31. 31. Worked Examples public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException,ExecutionException, TimeoutException; } Is this orthogonal?
  32. 32. Worked Examples The curse of non-orthogonality! // Would like to write: <A> Future<A> retryUntilSuccess(Future<A> future, Interval spacing) { // ??? } // Forced to write: A retryUntilSuccess(Future<A> future, Interval spacing, long timeout, TimeUnit unit) { // ... }
  33. 33. Worked Examples public interface Future<V> { Future<Tuple2<Future<V>, Function<Boolean, Future<Unit>>>> fork(); V unsafePerformGet() throws InterruptedException, ExecutionException; Future<V> timeout(long timeout, TimeUnit unit); } Future 2.0: Detangle ‘get’ and ‘timeout’
  34. 34. Worked Examples Is this orthogonal? static int compare( String str1, String str2, boolean nullIsLess)
  35. 35. Worked Examples Is this orthogonal? NullIsLess + Comparison NullIsLess Comparison static int compare( String str1, String str2, boolean nullIsLess)
  36. 36. Worked Examples The curse of non-orthogonality! List<String> myAlgorithm(List<String> list, boolean nullIsFirst) { // ... int c = compare(first, second, nullIsFirst); // ... }
  37. 37. enum Ordering { LT, EQ, GT } interface Ord<A> { Ordering compare(A l, A r); } Worked Examples 1. Define a unit of composition
  38. 38. class StringOrd extends Ord<String> { public Ordering compare(String l, String r) { // ... } } Worked Examples 2. Define one dimension (string comparison)
  39. 39. class NullIsLess<A> { private final Ord<A> ord; public NullIsLess(Ord<A> ord) { this.ord = ord; } public Ordering compare(A l, A r) { if (l == null) { if (r == null) return EQ; else return LT; } else if (r == null) return GT; else return ord.compare(l, r); } } Worked Examples 3. Define another dimension (null is first)
  40. 40. List<String> myAlgorithm(List<String> list, Ord<String> ord) { // ... Ordering c = ord.compare(first, second); // <- Beautiful!!! // ... } Ord<String> ord = new NullIsLess<String>(new StringOrd()); List<String> list2 = myAlgorithm(list, ord); Worked Examples 4. Compose orthogonal components
  41. 41. Worked Examples Is this orthogonal?* data MVar a putMVar :: MVar a -> a -> IO () takeMVar :: MVar a -> IO a *Thanks to Fabio the fabulous for this example.
  42. 42. Worked Examples Is this orthogonal? data MVar a putMVar :: MVar a -> a -> IO () takeMVar :: MVar a -> IO a Synchronization + Concurrency Synchronization Concurrency
  43. 43. Worked Examples data IORef a newtype Expect a = Expect a modify :: IORef a -> (a -> a) -> IO Bool data Promise a newPromise :: IO (Promise a, a -> IO ()) awaitPromise :: Promise a -> IO a Synchronization (IORef) Concurrency (Promise)
  44. 44. Worked Examples Is this orthogonal?* *A tiny part of Apache String Utils.
  45. 45. Worked Examples Is this orthogonal? ? ?
  46. 46. Worked Examples Is this orthogonal? data Parser a = Parser (String -> Either String (String, a)) char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a seq :: Parser a -> (a -> Parser b) -> Parser b pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b
  47. 47. Worked Examples Is this orthogonal?* data Parser a = Parser (String -> Either String (String, a)) char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a seq :: Parser a -> (a -> Parser b) -> Parser b pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b *Trick question — or is it?
  48. 48. Worked Examples Is this orthogonal? data Parser a = Parser (String -> ... char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a seq :: Parser a -> (a -> Parser b) -> Parser b pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b SequencingMapping Flattening
  49. 49. Worked Examples Is this orthogonal? data Parser a = Parser (String -> ... char :: Parser Char fail :: String -> Parser a alt :: Parser a -> Parser a -> Parser a join :: Parser (Parser a) -> Parser a pure :: a -> Parser a map :: (a -> b) -> Parser a -> Parser b Mapping Flattening
  50. 50. Wrap
  51. 51. Summary 1. Functional code is composable and orthogonal, allowing a small set of principled building blocks to snap together to solve complex problems in a predictable, reasonable way. 2. Composability measures the combinability of values. 3. Orthogonality measures the singular focus of primitive operations. 4. Refactor to orthogonality to obtain modular clode, uncluttered by irrelevant details.
  52. 52. Thank You! Special thanks to Reid, Cameron, Emily, & the wonderful Knoxville FP community, and the generous sponsor ResultStack! John A. De Goes — @jdegoes http://degoes.net

Weitere Verwandte Inhalte

Ähnliche Bücher

Kostenlos mit einer 30-tägigen Testversion von Scribd

Alle anzeigen

Ähnliche Hörbücher

Kostenlos mit einer 30-tägigen Testversion von Scribd

Alle anzeigen

×