From 095b1d1ee4a3037c95b5191254d97b49a3a054ae Mon Sep 17 00:00:00 2001
From: Evgenii Akentev <i@ak3n.com>
Date: Thu, 7 Jan 2021 20:49:51 +0500
Subject: [PATCH] Add README and more examples.

---
 .gitignore                                    |  1 +
 README.md                                     | 12 +++-
 backpack-handle/CHANGELOG.md                  |  5 --
 backpack-handle/Main.hs                       |  3 +-
 backpack-handle/backpack-handle.cabal         |  2 +-
 backpack-handle/domain/WeatherReporter.hs     | 22 +++++--
 backpack-handle/test/Test.hs                  | 11 ++--
 backpack-handles/LICENSE                      | 21 +++++++
 backpack-handles/Main.hs                      | 13 +++++
 backpack-handles/Setup.hs                     |  2 +
 backpack-handles/backpack-handles.cabal       | 57 +++++++++++++++++++
 backpack-handles/domain/WeatherProvider.hsig  | 14 +++++
 backpack-handles/domain/WeatherReporter.hsig  | 10 ++++
 backpack-handles/impl/SuperWeatherProvider.hs | 16 ++++++
 backpack-handles/impl/SuperWeatherReporter.hs | 25 ++++++++
 .../test-impl/TestWeatherProvider.hs          | 23 ++++++++
 backpack-handles/test/Test.hs                 | 23 ++++++++
 records-handle/CHANGELOG.md                   |  5 --
 records-handle/Main.hs                        |  3 +-
 records-handle/domain/WeatherReporter.hs      | 22 +++++--
 records-handle/records-handle.cabal           |  2 +-
 records-handle/test/Test.hs                   | 10 ++--
 simple-handle/CHANGELOG.md                    |  5 --
 simple-handle/Main.hs                         |  3 +-
 simple-handle/domain/WeatherReporter.hs       | 17 ++++--
 simple-handle/simple-handle.cabal             |  2 +-
 simple/LICENSE                                | 21 +++++++
 simple/Main.hs                                |  8 +++
 simple/Setup.hs                               |  2 +
 simple/domain/WeatherProvider.hs              | 12 ++++
 simple/domain/WeatherReporter.hs              | 16 ++++++
 simple/simple.cabal                           | 21 +++++++
 32 files changed, 362 insertions(+), 47 deletions(-)
 delete mode 100644 backpack-handle/CHANGELOG.md
 create mode 100644 backpack-handles/LICENSE
 create mode 100644 backpack-handles/Main.hs
 create mode 100644 backpack-handles/Setup.hs
 create mode 100644 backpack-handles/backpack-handles.cabal
 create mode 100644 backpack-handles/domain/WeatherProvider.hsig
 create mode 100644 backpack-handles/domain/WeatherReporter.hsig
 create mode 100644 backpack-handles/impl/SuperWeatherProvider.hs
 create mode 100644 backpack-handles/impl/SuperWeatherReporter.hs
 create mode 100644 backpack-handles/test-impl/TestWeatherProvider.hs
 create mode 100644 backpack-handles/test/Test.hs
 delete mode 100644 records-handle/CHANGELOG.md
 delete mode 100644 simple-handle/CHANGELOG.md
 create mode 100644 simple/LICENSE
 create mode 100644 simple/Main.hs
 create mode 100644 simple/Setup.hs
 create mode 100644 simple/domain/WeatherProvider.hs
 create mode 100644 simple/domain/WeatherReporter.hs
 create mode 100644 simple/simple.cabal

diff --git a/.gitignore b/.gitignore
index 4c9e245..bbdbf82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.DS_Store
 dist
 dist-*
 cabal-dev
diff --git a/README.md b/README.md
index 8b12c7c..d77edfb 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,11 @@
-# backpack-handle-example
+This repository contains examples of the Handle pattern. We start from `simple` that contains domain logic and iterate trying to use records and backpack as a way to test the domain logic.
 
-The examples of the Handle pattern in simple case, with records, and backpack.
+- `simple` is a library with two modules: `WeatherProvider` (provides data) and `WeatherReporter` (uses the data to create a report).
+
+- `simple-handle` introduces a single-implementation Handle to both modules.
+
+- `records-handle` implements a polymorphic Handle for `WeatherProvider` allowing us to replace the implementation and write tests for domain logic.
+
+- `backpack-handle` does the same thing as `records-handle` but using Backpack instead. It allows us to specialize function calls.
+
+- `backpack-handles` goes further and makes both `WeatherProvider` and `WeatherReporter` signatures. Unfortunately, it doesn't work yet.
diff --git a/backpack-handle/CHANGELOG.md b/backpack-handle/CHANGELOG.md
deleted file mode 100644
index 806c22c..0000000
--- a/backpack-handle/CHANGELOG.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Revision history for backpack-handle-pattern
-
-## 0.1.0.0 -- YYYY-mm-dd
-
-* First version. Released on an unsuspecting world.
diff --git a/backpack-handle/Main.hs b/backpack-handle/Main.hs
index 07cd3de..197df48 100644
--- a/backpack-handle/Main.hs
+++ b/backpack-handle/Main.hs
@@ -9,5 +9,6 @@ import qualified WeatherReporter
 main :: IO ()
 main = do
   let wph = SuperWeatherProvider.new
-  weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wph
+  let wrh = WeatherReporter.new wph
+  weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wrh
   putStrLn weatherReportInLondon
diff --git a/backpack-handle/backpack-handle.cabal b/backpack-handle/backpack-handle.cabal
index c427729..3bf756b 100644
--- a/backpack-handle/backpack-handle.cabal
+++ b/backpack-handle/backpack-handle.cabal
@@ -28,7 +28,7 @@ library test-impl
   default-language: Haskell2010
   build-depends:    base
 
-executable backpack-handle-exe
+executable main
   main-is:             Main.hs
   build-depends:       base >=4.13 && <4.14
                      , impl
diff --git a/backpack-handle/domain/WeatherReporter.hs b/backpack-handle/domain/WeatherReporter.hs
index e096750..8a521e9 100644
--- a/backpack-handle/domain/WeatherReporter.hs
+++ b/backpack-handle/domain/WeatherReporter.hs
@@ -1,11 +1,23 @@
 module WeatherReporter where
 
-import WeatherProvider
+import qualified WeatherProvider
 
 type WeatherReport = String
 
--- | This is domain logic. It uses `WeatherProvider` to get the actual data.
-getCurrentWeatherReportInLondon :: WeatherProvider.Handle -> IO WeatherReport
-getCurrentWeatherReportInLondon wph = do
+-- | We hide dependencies in the handle
+data Handle = Handle { weatherProvider :: WeatherProvider.Handle }
+
+-- | Constructor for Handle
+new :: WeatherProvider.Handle -> Handle
+new = Handle
+
+-- | Domain logic. Usually some pure code that might use mtl, free monads, etc.
+createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport
+createWeatherReport (WeatherProvider.WeatherData temp) =
+  "The current temperature in London is " ++ (show temp)
+
+-- | Domain logic that uses external dependency to get data and process it.
+getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport
+getCurrentWeatherReportInLondon (Handle wph) = do
   weatherData <- WeatherProvider.getWeatherData wph "London" "now"
-  return $ "Current temperature in London is " ++ (show $ temperature weatherData)
\ No newline at end of file
+  return $ createWeatherReport weatherData
diff --git a/backpack-handle/test/Test.hs b/backpack-handle/test/Test.hs
index 18dd2e5..83d1e92 100644
--- a/backpack-handle/test/Test.hs
+++ b/backpack-handle/test/Test.hs
@@ -1,22 +1,23 @@
 import Test.Hspec
 
-import qualified TestWeatherProvider
 import qualified WeatherProvider
 import qualified WeatherReporter
 
 main :: IO ()
 main = hspec spec
 
-weatherWithTemp :: WeatherProvider.Temperature -> WeatherProvider.Handle
-weatherWithTemp = TestWeatherProvider.new . TestWeatherProvider.Config 
+weatherWithTemp :: WeatherProvider.Temperature -> WeatherReporter.Handle
+weatherWithTemp = WeatherReporter.new
+  . WeatherProvider.new
+  . WeatherProvider.Config
 
 spec :: Spec
 spec = describe "WeatherReporter" $ do
   it "weather in London is 0" $ do
     weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $
       weatherWithTemp 0
-    weatherReportInLondon `shouldBe` "Current temperature in London is 0"
+    weatherReportInLondon `shouldBe` "The current temperature in London is 0"
   it "weather in London is -5" $ do
     weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $
       weatherWithTemp (-5)
-    weatherReportInLondon `shouldBe` "Current temperature in London is -5"
+    weatherReportInLondon `shouldBe` "The current temperature in London is -5"
diff --git a/backpack-handles/LICENSE b/backpack-handles/LICENSE
new file mode 100644
index 0000000..9eea539
--- /dev/null
+++ b/backpack-handles/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Evgenii Akentev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/backpack-handles/Main.hs b/backpack-handles/Main.hs
new file mode 100644
index 0000000..0e6baa0
--- /dev/null
+++ b/backpack-handles/Main.hs
@@ -0,0 +1,13 @@
+module Main where
+
+import qualified SuperWeatherProvider
+import qualified SuperWeatherReporter
+
+-- | This is an actual application where we use
+-- our concrete implementation of `WeatherProvider`.
+main :: IO ()
+main = do
+  let wph = SuperWeatherProvider.new
+  let wpr = SuperWeatherReporter.Handle wph
+  weatherReportInLondon <- SuperWeatherReporter.getCurrentWeatherReportInLondon wpr
+  putStrLn weatherReportInLondon
diff --git a/backpack-handles/Setup.hs b/backpack-handles/Setup.hs
new file mode 100644
index 0000000..9a994af
--- /dev/null
+++ b/backpack-handles/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/backpack-handles/backpack-handles.cabal b/backpack-handles/backpack-handles.cabal
new file mode 100644
index 0000000..e8ee369
--- /dev/null
+++ b/backpack-handles/backpack-handles.cabal
@@ -0,0 +1,57 @@
+cabal-version:       >=2
+name:                backpack-handles
+version:             0.1.0.0
+license-file:        LICENSE
+author:              Evgenii Akentev
+maintainer:          i@ak3n.com
+build-type:          Simple
+extra-source-files:  CHANGELOG.md
+
+library domain
+  hs-source-dirs: domain
+  signatures:      WeatherProvider
+  default-language: Haskell2010
+  build-depends:    base
+
+library domain-reporter
+  hs-source-dirs: domain
+  signatures:      WeatherReporter
+  default-language: Haskell2010
+  build-depends:    base, domain
+
+library impl
+  hs-source-dirs: impl
+  exposed-modules: SuperWeatherProvider
+                 , SuperWeatherReporter
+  reexported-modules: SuperWeatherProvider as WeatherProvider,
+    SuperWeatherReporter as WeatherReporter
+  default-language: Haskell2010
+  build-depends:    base
+
+library test-impl
+  hs-source-dirs: test-impl
+  exposed-modules: TestWeatherProvider
+  reexported-modules: TestWeatherProvider as WeatherProvider
+  default-language: Haskell2010
+  build-depends:    base
+
+executable main
+  main-is:             Main.hs
+  build-depends:       base >=4.13 && <4.14
+                     , impl
+                     , domain
+  default-language:    Haskell2010
+
+test-suite spec
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   test
+  main-is:          Test.hs
+  default-language:   Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , QuickCheck
+                     , hspec
+                     , domain
+                     , test-impl
+                     , impl
+  mixins:
+    impl (WeatherProvider as UnusedWeatherProvider, WeatherReporter)
diff --git a/backpack-handles/domain/WeatherProvider.hsig b/backpack-handles/domain/WeatherProvider.hsig
new file mode 100644
index 0000000..56de95a
--- /dev/null
+++ b/backpack-handles/domain/WeatherProvider.hsig
@@ -0,0 +1,14 @@
+signature WeatherProvider where
+
+data Temperature
+instance Show Temperature
+
+data WeatherData = WeatherData { temperature :: Temperature }
+
+type Location = String
+type Day = String
+
+data Handle
+
+-- | The interface of `WeatherProvider` with available methods.
+getWeatherData :: Handle -> Location -> Day -> IO WeatherData
diff --git a/backpack-handles/domain/WeatherReporter.hsig b/backpack-handles/domain/WeatherReporter.hsig
new file mode 100644
index 0000000..17ea47b
--- /dev/null
+++ b/backpack-handles/domain/WeatherReporter.hsig
@@ -0,0 +1,10 @@
+signature WeatherReporter where
+
+import qualified WeatherProvider
+
+type WeatherReport = String
+
+data Handle = Handle { weatherProvider :: WeatherProvider.Handle }
+
+-- | This is domain logic. It uses `WeatherProvider` to get the actual data.
+getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport
diff --git a/backpack-handles/impl/SuperWeatherProvider.hs b/backpack-handles/impl/SuperWeatherProvider.hs
new file mode 100644
index 0000000..1a29069
--- /dev/null
+++ b/backpack-handles/impl/SuperWeatherProvider.hs
@@ -0,0 +1,16 @@
+module SuperWeatherProvider where
+
+type Temperature = Int
+data WeatherData = WeatherData { temperature :: Temperature }
+
+type Location = String
+type Day = String
+
+data Handle = Handle
+
+new :: Handle
+new = Handle
+
+-- | This is some concrete implementation `WeatherProvider` interface
+getWeatherData :: Handle -> Location -> Day -> IO WeatherData
+getWeatherData _ _ _ = return $ WeatherData 30
diff --git a/backpack-handles/impl/SuperWeatherReporter.hs b/backpack-handles/impl/SuperWeatherReporter.hs
new file mode 100644
index 0000000..4a6ed2b
--- /dev/null
+++ b/backpack-handles/impl/SuperWeatherReporter.hs
@@ -0,0 +1,25 @@
+module SuperWeatherReporter where
+
+import qualified SuperWeatherProvider
+
+type WeatherReport = String
+
+type WeatherProviderHandle = SuperWeatherProvider.Handle
+
+-- | We hide dependencies in the handle
+data Handle = Handle { weatherProvider :: SuperWeatherProvider.Handle }
+
+-- | Constructor for Handle
+new :: SuperWeatherProvider.Handle -> Handle
+new = Handle
+
+-- | Domain logic. Usually some pure code that might use mtl, free monads, etc.
+createWeatherReport :: SuperWeatherProvider.WeatherData -> WeatherReport
+createWeatherReport (SuperWeatherProvider.WeatherData temp) =
+  "The current temperature in London is " ++ (show temp)
+
+-- | Domain logic that uses external dependency to get data and process it.
+getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport
+getCurrentWeatherReportInLondon (Handle wph) = do
+  weatherData <- SuperWeatherProvider.getWeatherData wph "London" "now"
+  return $ createWeatherReport weatherData
diff --git a/backpack-handles/test-impl/TestWeatherProvider.hs b/backpack-handles/test-impl/TestWeatherProvider.hs
new file mode 100644
index 0000000..900b102
--- /dev/null
+++ b/backpack-handles/test-impl/TestWeatherProvider.hs
@@ -0,0 +1,23 @@
+module TestWeatherProvider where
+
+type Temperature = Int
+data WeatherData = WeatherData { temperature :: Temperature }
+
+type Location = String
+type Day = String
+
+-- | This is a configuration that allows to setup the provider for tests.
+data Config = Config
+  { initTemperature :: Temperature
+  }
+
+data Handle = Handle
+  { config :: Config
+  }
+
+new :: Config -> Handle
+new = Handle
+
+-- | This is an implementation `WeatherProvider` interface for tests
+getWeatherData :: Handle -> Location -> Day -> IO WeatherData
+getWeatherData (Handle conf) _ _ = return $ WeatherData $ initTemperature conf
diff --git a/backpack-handles/test/Test.hs b/backpack-handles/test/Test.hs
new file mode 100644
index 0000000..b329480
--- /dev/null
+++ b/backpack-handles/test/Test.hs
@@ -0,0 +1,23 @@
+import Test.Hspec
+
+import qualified WeatherProvider
+import qualified WeatherReporter
+
+main :: IO ()
+main = hspec spec
+
+weatherWithTemp :: WeatherProvider.Temperature -> WeatherReporter.Handle
+weatherWithTemp t = WeatherReporter.new
+  $ WeatherProvider.new
+  $ WeatherProvider.Config t
+
+spec :: Spec
+spec = describe "WeatherReporter" $ do
+  it "weather in London is 0" $ do
+    weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $
+      weatherWithTemp 0
+    weatherReportInLondon `shouldBe` "The current temperature in London is 0"
+  it "weather in London is -5" $ do
+    weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $
+      weatherWithTemp (-5)
+    weatherReportInLondon `shouldBe` "The current temperature in London is -5"
diff --git a/records-handle/CHANGELOG.md b/records-handle/CHANGELOG.md
deleted file mode 100644
index 806c22c..0000000
--- a/records-handle/CHANGELOG.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Revision history for backpack-handle-pattern
-
-## 0.1.0.0 -- YYYY-mm-dd
-
-* First version. Released on an unsuspecting world.
diff --git a/records-handle/Main.hs b/records-handle/Main.hs
index 07cd3de..197df48 100644
--- a/records-handle/Main.hs
+++ b/records-handle/Main.hs
@@ -9,5 +9,6 @@ import qualified WeatherReporter
 main :: IO ()
 main = do
   let wph = SuperWeatherProvider.new
-  weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wph
+  let wrh = WeatherReporter.new wph
+  weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wrh
   putStrLn weatherReportInLondon
diff --git a/records-handle/domain/WeatherReporter.hs b/records-handle/domain/WeatherReporter.hs
index e096750..8a521e9 100644
--- a/records-handle/domain/WeatherReporter.hs
+++ b/records-handle/domain/WeatherReporter.hs
@@ -1,11 +1,23 @@
 module WeatherReporter where
 
-import WeatherProvider
+import qualified WeatherProvider
 
 type WeatherReport = String
 
--- | This is domain logic. It uses `WeatherProvider` to get the actual data.
-getCurrentWeatherReportInLondon :: WeatherProvider.Handle -> IO WeatherReport
-getCurrentWeatherReportInLondon wph = do
+-- | We hide dependencies in the handle
+data Handle = Handle { weatherProvider :: WeatherProvider.Handle }
+
+-- | Constructor for Handle
+new :: WeatherProvider.Handle -> Handle
+new = Handle
+
+-- | Domain logic. Usually some pure code that might use mtl, free monads, etc.
+createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport
+createWeatherReport (WeatherProvider.WeatherData temp) =
+  "The current temperature in London is " ++ (show temp)
+
+-- | Domain logic that uses external dependency to get data and process it.
+getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport
+getCurrentWeatherReportInLondon (Handle wph) = do
   weatherData <- WeatherProvider.getWeatherData wph "London" "now"
-  return $ "Current temperature in London is " ++ (show $ temperature weatherData)
\ No newline at end of file
+  return $ createWeatherReport weatherData
diff --git a/records-handle/records-handle.cabal b/records-handle/records-handle.cabal
index ac1318e..1540e7e 100644
--- a/records-handle/records-handle.cabal
+++ b/records-handle/records-handle.cabal
@@ -28,7 +28,7 @@ library test-impl
   build-depends:    base
                   , domain
 
-executable records-handle-exe
+executable main
   main-is:             Main.hs
   build-depends:       base >=4.13 && <4.14
                      , domain
diff --git a/records-handle/test/Test.hs b/records-handle/test/Test.hs
index 18dd2e5..7466dd4 100644
--- a/records-handle/test/Test.hs
+++ b/records-handle/test/Test.hs
@@ -7,16 +7,18 @@ import qualified WeatherReporter
 main :: IO ()
 main = hspec spec
 
-weatherWithTemp :: WeatherProvider.Temperature -> WeatherProvider.Handle
-weatherWithTemp = TestWeatherProvider.new . TestWeatherProvider.Config 
+weatherWithTemp :: WeatherProvider.Temperature -> WeatherReporter.Handle
+weatherWithTemp = WeatherReporter.new
+  . TestWeatherProvider.new
+  . TestWeatherProvider.Config
 
 spec :: Spec
 spec = describe "WeatherReporter" $ do
   it "weather in London is 0" $ do
     weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $
       weatherWithTemp 0
-    weatherReportInLondon `shouldBe` "Current temperature in London is 0"
+    weatherReportInLondon `shouldBe` "The current temperature in London is 0"
   it "weather in London is -5" $ do
     weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $
       weatherWithTemp (-5)
-    weatherReportInLondon `shouldBe` "Current temperature in London is -5"
+    weatherReportInLondon `shouldBe` "The current temperature in London is -5"
diff --git a/simple-handle/CHANGELOG.md b/simple-handle/CHANGELOG.md
deleted file mode 100644
index 806c22c..0000000
--- a/simple-handle/CHANGELOG.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Revision history for backpack-handle-pattern
-
-## 0.1.0.0 -- YYYY-mm-dd
-
-* First version. Released on an unsuspecting world.
diff --git a/simple-handle/Main.hs b/simple-handle/Main.hs
index e1d6702..c32c6e9 100644
--- a/simple-handle/Main.hs
+++ b/simple-handle/Main.hs
@@ -6,5 +6,6 @@ import qualified WeatherReporter
 main :: IO ()
 main = do
   let wph = WeatherProvider.new
-  weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wph
+  let wrh = WeatherReporter.new wph
+  weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wrh
   putStrLn weatherReportInLondon
diff --git a/simple-handle/domain/WeatherReporter.hs b/simple-handle/domain/WeatherReporter.hs
index 88a9d44..8a521e9 100644
--- a/simple-handle/domain/WeatherReporter.hs
+++ b/simple-handle/domain/WeatherReporter.hs
@@ -1,16 +1,23 @@
 module WeatherReporter where
 
-import WeatherProvider
+import qualified WeatherProvider
 
 type WeatherReport = String
 
+-- | We hide dependencies in the handle
+data Handle = Handle { weatherProvider :: WeatherProvider.Handle }
+
+-- | Constructor for Handle
+new :: WeatherProvider.Handle -> Handle
+new = Handle
+
 -- | Domain logic. Usually some pure code that might use mtl, free monads, etc.
-createWeatherReport :: WeatherData -> WeatherReport
-createWeatherReport (WeatherData temp) =
+createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport
+createWeatherReport (WeatherProvider.WeatherData temp) =
   "The current temperature in London is " ++ (show temp)
 
 -- | Domain logic that uses external dependency to get data and process it.
-getCurrentWeatherReportInLondon :: WeatherProvider.Handle -> IO WeatherReport
-getCurrentWeatherReportInLondon wph = do
+getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport
+getCurrentWeatherReportInLondon (Handle wph) = do
   weatherData <- WeatherProvider.getWeatherData wph "London" "now"
   return $ createWeatherReport weatherData
diff --git a/simple-handle/simple-handle.cabal b/simple-handle/simple-handle.cabal
index 2a349a8..94b079b 100644
--- a/simple-handle/simple-handle.cabal
+++ b/simple-handle/simple-handle.cabal
@@ -14,7 +14,7 @@ library domain
   default-language: Haskell2010
   build-depends:    base
 
-executable simple-handle-exe
+executable main
   main-is:             Main.hs
   build-depends:       base >=4.13 && <4.14
                      , domain
diff --git a/simple/LICENSE b/simple/LICENSE
new file mode 100644
index 0000000..9eea539
--- /dev/null
+++ b/simple/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Evgenii Akentev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/simple/Main.hs b/simple/Main.hs
new file mode 100644
index 0000000..c0cbd2b
--- /dev/null
+++ b/simple/Main.hs
@@ -0,0 +1,8 @@
+module Main where
+
+import qualified WeatherReporter
+
+main :: IO ()
+main = do
+  weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon
+  putStrLn weatherReportInLondon
diff --git a/simple/Setup.hs b/simple/Setup.hs
new file mode 100644
index 0000000..9a994af
--- /dev/null
+++ b/simple/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/simple/domain/WeatherProvider.hs b/simple/domain/WeatherProvider.hs
new file mode 100644
index 0000000..4cb6f5c
--- /dev/null
+++ b/simple/domain/WeatherProvider.hs
@@ -0,0 +1,12 @@
+module WeatherProvider where
+
+type Temperature = Int
+data WeatherData = WeatherData { temperature :: Temperature }
+
+type Location = String
+type Day = String
+
+-- | This is some concrete implementation.
+-- In this example we return a constant value.
+getWeatherData :: Location -> Day -> IO WeatherData
+getWeatherData _ _ = return $ WeatherData 30
diff --git a/simple/domain/WeatherReporter.hs b/simple/domain/WeatherReporter.hs
new file mode 100644
index 0000000..bc0d214
--- /dev/null
+++ b/simple/domain/WeatherReporter.hs
@@ -0,0 +1,16 @@
+module WeatherReporter where
+
+import qualified WeatherProvider
+
+type WeatherReport = String
+
+-- | Domain logic. Usually some pure code that might use mtl, free monads, etc.
+createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport
+createWeatherReport (WeatherProvider.WeatherData temp) =
+  "The current temperature in London is " ++ (show temp)
+
+-- | Domain logic that uses external dependency to get data and process it.
+getCurrentWeatherReportInLondon :: IO WeatherReport
+getCurrentWeatherReportInLondon = do
+  weatherData <- WeatherProvider.getWeatherData "London" "now"
+  return $ createWeatherReport weatherData
diff --git a/simple/simple.cabal b/simple/simple.cabal
new file mode 100644
index 0000000..3e84dad
--- /dev/null
+++ b/simple/simple.cabal
@@ -0,0 +1,21 @@
+cabal-version:       >=2
+name:                simple
+version:             0.1.0.0
+license-file:        LICENSE
+author:              Evgenii Akentev
+maintainer:          i@ak3n.com
+build-type:          Simple
+extra-source-files:  CHANGELOG.md
+
+library domain
+  hs-source-dirs: domain
+  exposed-modules: WeatherProvider
+                 , WeatherReporter
+  default-language: Haskell2010
+  build-depends:    base
+
+executable main
+  main-is:             Main.hs
+  build-depends:       base >=4.13 && <4.14
+                     , domain
+  default-language:    Haskell2010
-- 
2.34.1