diff --git a/avro.cabal b/avro.cabal
--- a/avro.cabal
+++ b/avro.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.4
 
 name:                   avro
-version:                0.5.2.0
+version:                0.5.2.1
 synopsis:               Avro serialization support for Haskell
 description:            Avro serialization and deserialization support for Haskell
 category:               Data
@@ -11,7 +11,7 @@
 maintainer:             Alexey Raga <alexey.raga@gmail.com>
 license:                BSD-3-Clause
 license-file:           LICENSE
-tested-with:            GHC == 8.10.1, GHC == 8.8.3, GHC == 8.6.5
+tested-with:            GHC == 8.10.2, GHC == 8.8.3, GHC == 8.6.5
 build-type:             Simple
 extra-source-files:     README.md
                         ChangeLog.md
@@ -57,12 +57,12 @@
 common data-binary-ieee754      { build-depends: data-binary-ieee754                                }
 common deepseq                  { build-depends: deepseq                                            }
 common directory                { build-depends: directory                                          }
-common doctest                  { build-depends: doctest                  >= 0.16.2     && < 0.17   }
+common doctest                  { build-depends: doctest                  >= 0.16.2     && < 0.19   }
 common doctest-discover         { build-depends: doctest-discover         >= 0.2        && < 0.3    }
 common extra                    { build-depends: extra                                              }
 common fail                     { build-depends: fail                                               }
 common gauge                    { build-depends: gauge                                              }
-common generic-lens             { build-depends: generic-lens                                       }
+common generic-lens             { build-depends: generic-lens             >= 1.2        && < 2.1    }
 common hashable                 { build-depends: hashable                                           }
 common hedgehog                 { build-depends: hedgehog                                           }
 common hw-hspec-hedgehog        { build-depends: hw-hspec-hedgehog                                  }
@@ -180,7 +180,7 @@
                       , zlib
   build-depends: avro
   type:                 exitcode-stdio-1.0
-  ghc-options:          -threaded
+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N
   default-language:     Haskell2010
   main-is:              Spec.hs
   build-tool-depends:   hspec-discover:hspec-discover
@@ -193,6 +193,7 @@
                         Avro.Codec.Int64Spec
                         Avro.Codec.MaybeSpec
                         Avro.Codec.NestedSpec
+                        Avro.Codec.NullSpec
                         Avro.Codec.TextSpec
                         Avro.Codec.ZigZagSpec
                         Avro.Data.Deconflict.Read
@@ -271,9 +272,10 @@
                       , doctest
                       , bytestring
                       , doctest-discover
+                      , zlib
   build-depends: avro
   type:                 exitcode-stdio-1.0
-  ghc-options:          -threaded
+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N
   main-is:              DoctestDriver.hs
   HS-Source-Dirs:       doctest
   build-tool-depends:   doctest-discover:doctest-discover
diff --git a/bench/Bench/Deconflict.hs b/bench/Bench/Deconflict.hs
--- a/bench/Bench/Deconflict.hs
+++ b/bench/Bench/Deconflict.hs
@@ -41,5 +41,5 @@
 container :: Benchmark
 container = env (many 1e5 newOuter >>= (\vs -> encodeContainerWithSchema nullCodec W.schema'Outer [Vector.toList vs])) $ \payload ->
   bgroup "Decoding container"
-    [ bench "From FromAvro" $ nf (\v -> decodeContainerWithReaderSchema @R.Outer R.schema'Outer v) payload
+    [ bench "From FromAvro" $ nf (decodeContainerWithReaderSchema @R.Outer R.schema'Outer) payload
     ]
diff --git a/bench/Bench/Encoding.hs b/bench/Bench/Encoding.hs
--- a/bench/Bench/Encoding.hs
+++ b/bench/Bench/Encoding.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Bench.Encoding
 where
 
diff --git a/src/Data/Avro.hs b/src/Data/Avro.hs
--- a/src/Data/Avro.hs
+++ b/src/Data/Avro.hs
@@ -1,9 +1,8 @@
 {-# LANGUAGE ConstraintKinds     #-}
 {-# LANGUAGE FlexibleInstances   #-}
-{-# LANGUAGE MultiWayIf          #-}
-{-# LANGUAGE PatternSynonyms     #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications    #-}
+
 -- | Avro encoding and decoding routines.
 --
 -- This library provides a high level interface for encoding and decoding
@@ -71,6 +70,8 @@
 import           Data.ByteString.Builder      (toLazyByteString)
 import qualified Data.ByteString.Lazy         as BL
 import           Data.Tagged                  (untag)
+
+{- HLINT ignore "Use section"         -}
 
 -- | Converts 'Schema' into 'ReadSchema'. This function may be useful when it is known
 -- that the writer and the reader schemas are the same.
diff --git a/src/Data/Avro/Codec.hs b/src/Data/Avro/Codec.hs
--- a/src/Data/Avro/Codec.hs
+++ b/src/Data/Avro/Codec.hs
@@ -89,7 +89,7 @@
         bytes
 
     decode :: G.Decoder a -> [Chunk] -> Either String (G.Decoder a)
-    decode !dec@G.Fail{} _ =
+    decode dec@G.Fail{} _ =
       -- short circuit if decoding failed
       pure dec
     decode !dec [] =
diff --git a/src/Data/Avro/Deriving.hs b/src/Data/Avro/Deriving.hs
--- a/src/Data/Avro/Deriving.hs
+++ b/src/Data/Avro/Deriving.hs
@@ -7,6 +7,8 @@
 {-# LANGUAGE TemplateHaskell    #-}
 {-# LANGUAGE TypeApplications   #-}
 
+{- HLINT ignore "Avoid lambda using `infix`" -}
+
 -- | This module lets us derive Haskell types from an Avro schema that
 -- can be serialized/deserialzed to Avro.
 module Data.Avro.Deriving
@@ -79,8 +81,7 @@
 import qualified Data.Text                  as T
 import qualified Data.Vector                as V
 
-import Data.Avro.Deriving.Lift    ()
-import Language.Haskell.TH.Syntax (lift)
+import Data.Avro.Deriving.Lift ()
 
 -- | How to treat Avro namespaces in the generated Haskell types.
 data NamespaceBehavior =
@@ -386,7 +387,7 @@
       let con = conP (mkDataTypeName (namespaceBehavior opts) n) (varP <$> names)
       lamE [wn, con]
             [| mconcat $( let build (fld, n) = [| toAvro (fldType fld) $(varE n) |]
-                          in listE $ build <$> (zip fs names)
+                          in listE $ build <$> zip fs names
                         )
             |]
 
@@ -403,7 +404,7 @@
 genToAvro _ _ = pure []
 
 schemaDef :: Name -> Schema -> Q [Dec]
-schemaDef sname sch = setName sname $
+schemaDef sname sch = setName sname
   [d|
       x :: Schema
       x = sch
@@ -426,7 +427,7 @@
   sequenceA [genDataType dname flds]
 genType opts (S.Enum n _ _ vs) = do
   let dname = mkDataTypeName (namespaceBehavior opts) n
-  sequenceA [genEnum dname (mkAdtCtorName (namespaceBehavior opts) n <$> (V.toList vs))]
+  sequenceA [genEnum dname (mkAdtCtorName (namespaceBehavior opts) n <$> V.toList vs)]
 genType opts (S.Fixed n _ s _) = do
   let dname = mkDataTypeName (namespaceBehavior opts) n
   sequenceA [genNewtype dname]
@@ -434,6 +435,7 @@
 
 mkFieldTypeName :: NamespaceBehavior -> S.Schema -> Q TH.Type
 mkFieldTypeName namespaceBehavior = \case
+  S.Null             -> [t| () |]
   S.Boolean          -> [t| Bool |]
   S.Long (Just (DecimalL (Decimal p s)))
                      -> [t| Decimal $(litT $ numTyLit p) $(litT $ numTyLit s) |]
@@ -460,7 +462,6 @@
   S.NamedType n      -> [t| $(conT $ mkDataTypeName namespaceBehavior n)|]
   S.Fixed n _ _ _    -> [t| $(conT $ mkDataTypeName namespaceBehavior n)|]
   S.Enum n _ _ _     -> [t| $(conT $ mkDataTypeName namespaceBehavior n)|]
-  t                  -> error $ "Avro type is not supported: " <> show t
   where go = mkFieldTypeName namespaceBehavior
         union = \case
           []              ->
@@ -539,7 +540,7 @@
 mkField opts typeName field = do
   ftype <- mkFieldTypeName (namespaceBehavior opts) (fldType field)
   let prefix = renderName (namespaceBehavior opts) typeName
-      fName = mkTextName $ (fieldNameBuilder opts) prefix field
+      fName = mkTextName $ fieldNameBuilder opts prefix field
       (fieldStrictness, fieldUnpackedness) =
         fieldRepresentation opts typeName field
       strictness =
diff --git a/src/Data/Avro/EitherN.hs b/src/Data/Avro/EitherN.hs
--- a/src/Data/Avro/EitherN.hs
+++ b/src/Data/Avro/EitherN.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
@@ -322,8 +320,8 @@
   bitraverse _ _ (E7_3 a) = pure (E7_3 a)
   bitraverse _ _ (E7_4 a) = pure (E7_4 a)
   bitraverse _ _ (E7_5 a) = pure (E7_5 a)
-  bitraverse f _ (E7_6 a) = E7_6 <$> (f a)
-  bitraverse _ g (E7_7 a) = E7_7 <$> (g a)
+  bitraverse f _ (E7_6 a) = E7_6 <$> f a
+  bitraverse _ g (E7_7 a) = E7_7 <$> g a
 
 instance Bitraversable (Either8 a b c d e f) where
   bitraverse _ _ (E8_1 a) = pure (E8_1 a)
@@ -332,8 +330,8 @@
   bitraverse _ _ (E8_4 a) = pure (E8_4 a)
   bitraverse _ _ (E8_5 a) = pure (E8_5 a)
   bitraverse _ _ (E8_6 a) = pure (E8_6 a)
-  bitraverse f _ (E8_7 a) = E8_7 <$> (f a)
-  bitraverse _ g (E8_8 a) = E8_8 <$> (g a)
+  bitraverse f _ (E8_7 a) = E8_7 <$> f a
+  bitraverse _ g (E8_8 a) = E8_8 <$> g a
 
 instance Bitraversable (Either9 a b c d e f g) where
   bitraverse _ _ (E9_1 a) = pure (E9_1 a)
@@ -343,8 +341,8 @@
   bitraverse _ _ (E9_5 a) = pure (E9_5 a)
   bitraverse _ _ (E9_6 a) = pure (E9_6 a)
   bitraverse _ _ (E9_7 a) = pure (E9_7 a)
-  bitraverse f _ (E9_8 a) = E9_8 <$> (f a)
-  bitraverse _ g (E9_9 a) = E9_9 <$> (g a)
+  bitraverse f _ (E9_8 a) = E9_8 <$> f a
+  bitraverse _ g (E9_9 a) = E9_9 <$> g a
 
 instance Bitraversable (Either10 a b c d e f g h) where
   bitraverse _ _ (E10_1 a)  = pure (E10_1 a)
@@ -355,8 +353,8 @@
   bitraverse _ _ (E10_6 a)  = pure (E10_6 a)
   bitraverse _ _ (E10_7 a)  = pure (E10_7 a)
   bitraverse _ _ (E10_8 a)  = pure (E10_8 a)
-  bitraverse f _ (E10_9 a)  = E10_9 <$> (f a)
-  bitraverse _ g (E10_10 a) = E10_10 <$> (g a)
+  bitraverse f _ (E10_9 a)  = E10_9 <$> f a
+  bitraverse _ g (E10_10 a) = E10_10 <$> g a
 
 instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c) => HasAvroSchema (Either3 a b c) where
   schema = Tagged $ mkUnion (untag @a schema :| [
diff --git a/src/Data/Avro/Encoding/FromAvro.hs b/src/Data/Avro/Encoding/FromAvro.hs
--- a/src/Data/Avro/Encoding/FromAvro.hs
+++ b/src/Data/Avro/Encoding/FromAvro.hs
@@ -32,6 +32,7 @@
 import qualified Data.HashMap.Strict         as HashMap
 import           Data.Int
 import           Data.List.NonEmpty          (NonEmpty)
+import           Data.Foldable               (traverse_)
 import qualified Data.Map                    as Map
 import           Data.Text                   (Text)
 import qualified Data.Text                   as Text
@@ -130,6 +131,11 @@
   fromAvro x           = Left ("Unable to decode Double from: " <> show (describeValue x))
   {-# INLINE fromAvro #-}
 
+instance FromAvro () where
+  fromAvro Null = Right ()
+  fromAvro x    = Left ("Unable to decode () from: " <> show (describeValue x))
+  {-# INLINE fromAvro #-}
+
 instance FromAvro Bool where
   fromAvro (Boolean x) = Right x
   fromAvro x           = Left ("Unable to decode Bool from: " <> show (describeValue x))
@@ -310,22 +316,17 @@
     vs <- replicateM (fromIntegral blockLength) (getField env t)
     (vs:) <$> getBlocksOf env t
 
-writeByPositions :: MV.MVector s Value -> [(Int, Value)] -> ST s ()
-writeByPositions mv writes = foldl (>>) (return ()) (fmap (go mv) writes)
-  where go :: MV.MVector s Value ->  (Int, Value) -> ST s ()
-        go mv (n, v) = MV.write mv n v
-
 getRecord :: HashMap Schema.TypeName ReadSchema -> [ReadSchema.ReadField] -> Get (Vector Value)
 getRecord env fs = do
-  moos <- forM fs $ \f ->
+  moos <- fmap concat . forM fs $ \f ->
     case ReadSchema.fldStatus f of
-      ReadSchema.Ignored       -> getField env (ReadSchema.fldType f) >> pure []
-      ReadSchema.AsIs i        -> fmap ((:[]) . (i, )) (getField env (ReadSchema.fldType f))
+      ReadSchema.Ignored       -> [] <$ getField env (ReadSchema.fldType f)
+      ReadSchema.AsIs i        -> (\f -> [(i,f)]) <$> getField env (ReadSchema.fldType f)
       ReadSchema.Defaulted i v -> pure [(i, convertValue v)] --undefined
 
   return $ V.create $ do
-    vals <- MV.unsafeNew (length fs)
-    writeByPositions vals (mconcat moos)
+    vals <- MV.unsafeNew (length moos)
+    traverse_ (uncurry (MV.write vals)) moos
     return vals
 
 -- | This function will be unnecessary when we fully migrate to 'Value'
diff --git a/src/Data/Avro/Encoding/ToAvro.hs b/src/Data/Avro/Encoding/ToAvro.hs
--- a/src/Data/Avro/Encoding/ToAvro.hs
+++ b/src/Data/Avro/Encoding/ToAvro.hs
@@ -6,7 +6,6 @@
 {-# LANGUAGE TypeApplications          #-}
 {-# LANGUAGE TypeFamilies              #-}
 
-
 module Data.Avro.Encoding.ToAvro
 where
 
@@ -40,6 +39,8 @@
 import           Data.Word
 import           GHC.TypeLits
 
+{- HLINT ignore "Use section"         -}
+
 newtype Encoder = Encoder { runEncoder :: Schema -> Builder }
 
 (.=) :: forall a. ToAvro a => Text -> a -> (Text, Encoder)
@@ -74,45 +75,45 @@
 instance ToAvro Int32 where
   toAvro (S.Long _) i = encodeRaw @Int64 (fromIntegral i)
   toAvro (S.Int _) i  = encodeRaw @Int32 i
-  toAvro S.Double i   = toAvro @Double (S.Double) (fromIntegral i)
-  toAvro S.Float i    = toAvro @Float (S.Float) (fromIntegral i)
+  toAvro S.Double i   = toAvro @Double S.Double (fromIntegral i)
+  toAvro S.Float i    = toAvro @Float S.Float (fromIntegral i)
   toAvro s _          = error ("Unable to encode Int32 as: " <> show s)
   {-# INLINE toAvro #-}
 
 instance ToAvro Int64 where
   toAvro (S.Long _) i = encodeRaw @Int64 i
-  toAvro S.Double i   = toAvro @Double (S.Double) (fromIntegral i)
-  toAvro S.Float i    = toAvro @Float (S.Float) (fromIntegral i)
+  toAvro S.Double i   = toAvro @Double S.Double (fromIntegral i)
+  toAvro S.Float i    = toAvro @Float S.Float (fromIntegral i)
   toAvro s _          = error ("Unable to encode Int64 as: " <> show s)
   {-# INLINE toAvro #-}
 
 instance ToAvro Word8 where
   toAvro (S.Int _) i  = encodeRaw @Word8 i
   toAvro (S.Long _) i = encodeRaw @Word64 (fromIntegral i)
-  toAvro S.Double i   = toAvro @Double (S.Double) (fromIntegral i)
-  toAvro S.Float i    = toAvro @Float (S.Float) (fromIntegral i)
+  toAvro S.Double i   = toAvro @Double S.Double (fromIntegral i)
+  toAvro S.Float i    = toAvro @Float S.Float (fromIntegral i)
   toAvro s _          = error ("Unable to encode Word8 as: " <> show s)
   {-# INLINE toAvro #-}
 
 instance ToAvro Word16 where
   toAvro (S.Int _) i  = encodeRaw @Word16 i
   toAvro (S.Long _) i = encodeRaw @Word64 (fromIntegral i)
-  toAvro S.Double i   = toAvro @Double (S.Double) (fromIntegral i)
-  toAvro S.Float i    = toAvro @Float (S.Float) (fromIntegral i)
+  toAvro S.Double i   = toAvro @Double S.Double (fromIntegral i)
+  toAvro S.Float i    = toAvro @Float S.Float (fromIntegral i)
   toAvro s _          = error ("Unable to encode Word16 as: " <> show s)
   {-# INLINE toAvro #-}
 
 instance ToAvro Word32 where
   toAvro (S.Int _) i  = encodeRaw @Word32 i
   toAvro (S.Long _) i = encodeRaw @Word64 (fromIntegral i)
-  toAvro S.Double i   = toAvro @Double (S.Double) (fromIntegral i)
-  toAvro S.Float i    = toAvro @Float (S.Float) (fromIntegral i)
+  toAvro S.Double i   = toAvro @Double S.Double (fromIntegral i)
+  toAvro S.Float i    = toAvro @Float S.Float (fromIntegral i)
   toAvro s _          = error ("Unable to encode Word32 as: " <> show s)
   {-# INLINE toAvro #-}
 
 instance ToAvro Word64 where
   toAvro (S.Long _) i = encodeRaw @Word64 i
-  toAvro S.Double i   = toAvro @Double (S.Double) (fromIntegral i)
+  toAvro S.Double i   = toAvro @Double S.Double (fromIntegral i)
   toAvro s _          = error ("Unable to encode Word64 as: " <> show s)
   {-# INLINE toAvro #-}
 
@@ -127,6 +128,10 @@
   toAvro s _        = error ("Unable to encode Float as: " <> show s)
   {-# INLINE toAvro #-}
 
+instance ToAvro () where
+  toAvro S.Null () = mempty
+  toAvro s ()      = error ("Unable to encode () as: " <> show s)
+
 instance ToAvro Bool where
   toAvro S.Boolean v = word8 $ fromIntegral (fromEnum v)
   toAvro s _         = error ("Unable to encode Bool as: " <> show s)
@@ -218,19 +223,20 @@
   toAvro (S.Union opts) v =
     case F.toList opts of
       [S.Null, s] -> maybe (putI 0) (\a -> putI 1 <> toAvro s a) v
+      [s, S.Null] -> maybe (putI 1) (\a -> putI 0 <> toAvro s a) v
       wrongOpts   -> error ("Unable to encode Maybe as " <> show wrongOpts)
   toAvro s _ = error ("Unable to encode Maybe as " <> show s)
 
 instance (ToAvro a) => ToAvro (Identity a) where
   toAvro (S.Union opts) e@(Identity a) =
-    if (V.length opts == 1)
+    if V.length opts == 1
       then putI 0 <> toAvro (V.unsafeIndex opts 0) a
       else error ("Unable to encode Identity as a single-value union: " <> show opts)
   toAvro s _ = error ("Unable to encode Identity value as " <> show s)
 
 instance (ToAvro a, ToAvro b) => ToAvro (Either a b) where
   toAvro (S.Union opts) v =
-    if (V.length opts == 2)
+    if V.length opts == 2
       then case v of
         Left a  -> putI 0 <> toAvro (V.unsafeIndex opts 0) a
         Right b -> putI 1 <> toAvro (V.unsafeIndex opts 1) b
diff --git a/src/Data/Avro/Internal/Container.hs b/src/Data/Avro/Internal/Container.hs
--- a/src/Data/Avro/Internal/Container.hs
+++ b/src/Data/Avro/Internal/Container.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE LambdaCase          #-}
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE RankNTypes          #-}
 {-# LANGUAGE RecordWildCards     #-}
@@ -5,6 +6,7 @@
 {-# LANGUAGE StrictData          #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Data.Avro.Internal.Container
 where
 
@@ -98,7 +100,7 @@
       in Right (containedSchema, blocks)
   where
     allBlocks sync decompress bytes =
-      flip unfoldr (Just bytes) $ \acc -> case acc of
+      flip unfoldr (Just bytes) $ \case
         Just rest -> next sync decompress rest
         Nothing   -> Nothing
 
diff --git a/src/Data/Avro/Internal/DecodeRaw.hs b/src/Data/Avro/Internal/DecodeRaw.hs
--- a/src/Data/Avro/Internal/DecodeRaw.hs
+++ b/src/Data/Avro/Internal/DecodeRaw.hs
@@ -12,7 +12,7 @@
 getNonNegative :: (Bits i, Integral i) => Get i
 getNonNegative = do
   orig <- getWord8s
-  return $! (foldl' (\a x -> (a `shiftL` 7) + fromIntegral x) 0 (reverse orig))
+  return $! foldl' (\a x -> (a `shiftL` 7) + fromIntegral x) 0 (reverse orig)
 
 getWord8s :: Get [Word8]
 getWord8s = do
diff --git a/src/Data/Avro/Schema/Schema.hs b/src/Data/Avro/Schema/Schema.hs
--- a/src/Data/Avro/Schema/Schema.hs
+++ b/src/Data/Avro/Schema/Schema.hs
@@ -1,9 +1,6 @@
 {-# LANGUAGE CPP                   #-}
 {-# LANGUAGE DeriveAnyClass        #-}
-{-# LANGUAGE DeriveFoldable        #-}
-{-# LANGUAGE DeriveFunctor         #-}
 {-# LANGUAGE DeriveGeneric         #-}
-{-# LANGUAGE DeriveTraversable     #-}
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE LambdaCase            #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
@@ -61,6 +58,7 @@
 
 import           Control.Applicative
 import           Control.DeepSeq            (NFData)
+import           Control.Monad
 import           Control.Monad.Except
 import qualified Control.Monad.Fail         as MF
 import           Control.Monad.State.Strict
@@ -92,6 +90,9 @@
 import           Prelude                as P
 
 import GHC.Generics (Generic)
+
+{- HLINT ignore "Reduce duplication"  -}
+{- HLINT ignore "Use &&"              -}
 
 data DefaultValue
       = DNull
diff --git a/test/Avro/Codec/ArraySpec.hs b/test/Avro/Codec/ArraySpec.hs
--- a/test/Avro/Codec/ArraySpec.hs
+++ b/test/Avro/Codec/ArraySpec.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE ScopedTypeVariables #-}
+
 module Avro.Codec.ArraySpec (spec) where
 
 import           Data.Avro.Schema.ReadSchema (fromSchema)
@@ -17,13 +18,13 @@
 import qualified Hedgehog.Range              as Range
 import           Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Codec.ArraySpec" $ do
   it "list roundtip" $ require $ property $ do
     let schema   = Schema.Array (Schema.Int Nothing)
-    let arrayGen = Gen.list (Range.linear 0 255) (Gen.int32 (Range.linearBounded))
+    let arrayGen = Gen.list (Range.linear 0 255) (Gen.int32 Range.linearBounded)
     roundtripGen schema arrayGen
 
   it "map roundtrip" $ require $ property $ do
@@ -36,10 +37,10 @@
 
   it "vector roundtrip" $ require $ property $ do
     let schema   = Schema.Array (Schema.Int Nothing)
-    let arrayGen = Gen.list (Range.linear 0 255) (Gen.int32 (Range.linearBounded))
+    let arrayGen = Gen.list (Range.linear 0 255) (Gen.int32 Range.linearBounded)
     roundtripGen schema (V.fromList <$> arrayGen)
 
   it "unboxed vector roundtrip" $ require $ property $ do
     let schema   = Schema.Array (Schema.Int Nothing)
-    let arrayGen = Gen.list (Range.linear 0 255) (Gen.int32 (Range.linearBounded))
+    let arrayGen = Gen.list (Range.linear 0 255) (Gen.int32 Range.linearBounded)
     roundtripGen schema (U.fromList <$> arrayGen)
diff --git a/test/Avro/Codec/BoolSpec.hs b/test/Avro/Codec/BoolSpec.hs
--- a/test/Avro/Codec/BoolSpec.hs
+++ b/test/Avro/Codec/BoolSpec.hs
@@ -17,7 +17,7 @@
 import Data.Avro          (encodeValueWithSchema)
 import Data.Avro.Deriving (deriveAvroFromByteString, r)
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroFromByteString [r|
 {
diff --git a/test/Avro/Codec/CodecRawSpec.hs b/test/Avro/Codec/CodecRawSpec.hs
--- a/test/Avro/Codec/CodecRawSpec.hs
+++ b/test/Avro/Codec/CodecRawSpec.hs
@@ -11,7 +11,7 @@
 import           Test.Hspec
 import qualified Test.QuickCheck              as Q
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Codec.CodecRawSpec" $ do
diff --git a/test/Avro/Codec/DoubleSpec.hs b/test/Avro/Codec/DoubleSpec.hs
--- a/test/Avro/Codec/DoubleSpec.hs
+++ b/test/Avro/Codec/DoubleSpec.hs
@@ -18,7 +18,7 @@
 import qualified Data.Avro.Schema.Schema as Schema
 import qualified Data.ByteString.Lazy    as BL
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroFromByteString [r|
 {
diff --git a/test/Avro/Codec/FloatSpec.hs b/test/Avro/Codec/FloatSpec.hs
--- a/test/Avro/Codec/FloatSpec.hs
+++ b/test/Avro/Codec/FloatSpec.hs
@@ -19,7 +19,7 @@
 import qualified Data.Avro.Schema.Schema as Schema
 import qualified Data.ByteString.Lazy    as BL
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroFromByteString [r|
 {
diff --git a/test/Avro/Codec/Int64Spec.hs b/test/Avro/Codec/Int64Spec.hs
--- a/test/Avro/Codec/Int64Spec.hs
+++ b/test/Avro/Codec/Int64Spec.hs
@@ -25,7 +25,7 @@
 import           Data.Avro.Deriving      (deriveAvroFromByteString, r)
 import qualified Data.Avro.Schema.Schema as Schema
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroFromByteString [r|
 {
diff --git a/test/Avro/Codec/MaybeSpec.hs b/test/Avro/Codec/MaybeSpec.hs
--- a/test/Avro/Codec/MaybeSpec.hs
+++ b/test/Avro/Codec/MaybeSpec.hs
@@ -14,7 +14,7 @@
 import           Data.Avro.Deriving      (deriveAvroFromByteString, r)
 import qualified Data.Avro.Schema.Schema as Schema
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroFromByteString [r|
 {
@@ -25,7 +25,19 @@
 }
 |]
 
+deriveAvroFromByteString [r|
+{
+  "type": "record",
+  "name": "OnlyMaybeBool'",
+  "namespace": "test.contract",
+  "fields": [ {"name": "onlyMaybeBoolValue", "type": ["boolean", "null"]} ]
+}
+|]
+
 spec :: Spec
 spec = describe "Avro.Codec.MaybeSpec" $ do
   it "should encode then decode Maybe Bool correctly" $ require $ property $ do
     roundtripGen schema'OnlyMaybeBool (OnlyMaybeBool <$> Gen.maybe Gen.bool)
+
+  it "should be able to roundtrip a Maybe Bool defined with flipped union type" $ require $ property $ do
+    roundtripGen schema'OnlyMaybeBool' (OnlyMaybeBool' <$> Gen.maybe Gen.bool)
diff --git a/test/Avro/Codec/NestedSpec.hs b/test/Avro/Codec/NestedSpec.hs
--- a/test/Avro/Codec/NestedSpec.hs
+++ b/test/Avro/Codec/NestedSpec.hs
@@ -15,7 +15,7 @@
 import           Data.Avro.Deriving      (deriveAvroFromByteString, r)
 import qualified Data.Avro.Schema.Schema as Schema
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroFromByteString [r|
 {
diff --git a/test/Avro/Codec/NullSpec.hs b/test/Avro/Codec/NullSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Avro/Codec/NullSpec.hs
@@ -0,0 +1,87 @@
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE OverloadedLists   #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes       #-}
+{-# LANGUAGE StrictData        #-}
+{-# LANGUAGE TemplateHaskell   #-}
+module Avro.Codec.NullSpec (spec) where
+
+import           Avro.TestUtils
+import qualified Data.Avro.Schema.Schema     as Schema
+import           Data.Text                   (Text)
+import           HaskellWorks.Hspec.Hedgehog
+import           Hedgehog
+import qualified Hedgehog.Gen                as Gen
+import           Test.Hspec
+
+import qualified Data.ByteString.Lazy as BL
+
+import Data.Avro          (encodeValueWithSchema)
+import Data.Avro.Deriving (deriveAvroFromByteString, r)
+import Data.Avro.EitherN  (Either3 (E3_1, E3_3))
+
+{- HLINT ignore "Redundant do"        -}
+
+deriveAvroFromByteString [r|
+{
+  "type": "record",
+  "name": "OnlyNull",
+  "namespace": "test.contract",
+  "fields": [ {"name": "onlyNullValue", "type": "null"} ]
+}
+|]
+
+deriveAvroFromByteString [r|
+{
+  "type": "record",
+  "name": "NullInUnion1",
+  "namespace": "test.contract",
+  "fields": [ {"name": "nullInUnion1", "type": ["null", "string", "boolean"] } ]
+}
+|]
+
+deriveAvroFromByteString [r|
+{
+  "type": "record",
+  "name": "NullInUnion3",
+  "namespace": "test.contract",
+  "fields": [ {"name": "nullInUnion3", "type": ["string", "boolean", "null"] } ]
+}
+|]
+
+nullEncoding :: BL.ByteString
+nullEncoding = mempty
+
+spec :: Spec
+spec = describe "Avro.Codec.NullSpec" $ do
+  it "should encode () correctly" $ require $ withTests 1 $ property $ do
+    encodeValueWithSchema Schema.Null (OnlyNull ()) === nullEncoding
+
+  it "should encode then decode () correctly" $ require $ withTests 1 $ property $ do
+    roundtripGen Schema.Null (pure ())
+
+  it "should encode () in union (first) correctly" $ require $ withTests 1 $ property $ do
+    let index = encodeValueWithSchema Schema.Int' (0 :: Int)
+        nullFirstEncoding = index <> nullEncoding
+    encodeValueWithSchema
+      (Schema.Union [Schema.Null, Schema.String', Schema.Boolean])
+      (E3_1 () :: Either3 () Text Bool)
+      === nullFirstEncoding
+
+  it "should encode then decode () in union (first) correctly" $ require $ withTests 1 $ property $ do
+    roundtripGen
+      (Schema.Union [Schema.Null, Schema.String', Schema.Boolean])
+      (pure (E3_1 () :: Either3 () Text Bool))
+
+  it "should encode () in union (last) correctly" $ require $ withTests 1 $ property $ do
+    let index = encodeValueWithSchema Schema.Int' (2 :: Int)
+        nullLastEncoding = index <> nullEncoding
+    encodeValueWithSchema
+      (Schema.Union [Schema.String', Schema.Boolean, Schema.Null])
+      (E3_3 () :: Either3 Text Bool ())
+      === nullLastEncoding
+
+  it "should encode then decode () in union (last) correctly" $ require $ withTests 1 $ property $ do
+    roundtripGen
+      (Schema.Union [Schema.String', Schema.Boolean, Schema.Null])
+      (pure (E3_3 () :: Either3 Text Bool ()))
diff --git a/test/Avro/Codec/TextSpec.hs b/test/Avro/Codec/TextSpec.hs
--- a/test/Avro/Codec/TextSpec.hs
+++ b/test/Avro/Codec/TextSpec.hs
@@ -20,7 +20,7 @@
 import           Data.Avro.Schema.ReadSchema (fromSchema)
 import qualified Data.Avro.Schema.Schema     as Schema
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroFromByteString [r|
 {
diff --git a/test/Avro/Codec/ZigZagSpec.hs b/test/Avro/Codec/ZigZagSpec.hs
--- a/test/Avro/Codec/ZigZagSpec.hs
+++ b/test/Avro/Codec/ZigZagSpec.hs
@@ -10,7 +10,7 @@
 import Test.Hspec
 import Test.QuickCheck
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Codec.Int64Spec" $ do
diff --git a/test/Avro/Data/Deconflict/Write.hs b/test/Avro/Data/Deconflict/Write.hs
--- a/test/Avro/Data/Deconflict/Write.hs
+++ b/test/Avro/Data/Deconflict/Write.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Deconflict.Write where
 
 import Data.Avro.Deriving
diff --git a/test/Avro/Data/Endpoint.hs b/test/Avro/Data/Endpoint.hs
--- a/test/Avro/Data/Endpoint.hs
+++ b/test/Avro/Data/Endpoint.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Endpoint
 where
 
diff --git a/test/Avro/Data/Enums.hs b/test/Avro/Data/Enums.hs
--- a/test/Avro/Data/Enums.hs
+++ b/test/Avro/Data/Enums.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Enums
 where
 
diff --git a/test/Avro/Data/FixedTypes.hs b/test/Avro/Data/FixedTypes.hs
--- a/test/Avro/Data/FixedTypes.hs
+++ b/test/Avro/Data/FixedTypes.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.FixedTypes
 where
 
diff --git a/test/Avro/Data/Karma.hs b/test/Avro/Data/Karma.hs
--- a/test/Avro/Data/Karma.hs
+++ b/test/Avro/Data/Karma.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Karma
 where
 
diff --git a/test/Avro/Data/Logical.hs b/test/Avro/Data/Logical.hs
--- a/test/Avro/Data/Logical.hs
+++ b/test/Avro/Data/Logical.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Logical
 where
 
diff --git a/test/Avro/Data/Maybe.hs b/test/Avro/Data/Maybe.hs
--- a/test/Avro/Data/Maybe.hs
+++ b/test/Avro/Data/Maybe.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Maybe
 where
 
diff --git a/test/Avro/Data/Recursive.hs b/test/Avro/Data/Recursive.hs
--- a/test/Avro/Data/Recursive.hs
+++ b/test/Avro/Data/Recursive.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Recursive
 where
 
diff --git a/test/Avro/Data/Reused.hs b/test/Avro/Data/Reused.hs
--- a/test/Avro/Data/Reused.hs
+++ b/test/Avro/Data/Reused.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Reused
 where
 
diff --git a/test/Avro/Data/Unions.hs b/test/Avro/Data/Unions.hs
--- a/test/Avro/Data/Unions.hs
+++ b/test/Avro/Data/Unions.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE DeriveAnyClass      #-}
-{-# LANGUAGE DeriveFoldable      #-}
-{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE NumDecimals         #-}
@@ -13,6 +11,7 @@
 {-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Data.Unions
 where
 
diff --git a/test/Avro/Decode/ContainerSpec.hs b/test/Avro/Decode/ContainerSpec.hs
--- a/test/Avro/Decode/ContainerSpec.hs
+++ b/test/Avro/Decode/ContainerSpec.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TemplateHaskell     #-}
+
 module Avro.Decode.ContainerSpec
 where
 
@@ -17,7 +17,7 @@
 import qualified Hedgehog.Range              as Range
 import           Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = do
diff --git a/test/Avro/Decode/RawBlocksSpec.hs b/test/Avro/Decode/RawBlocksSpec.hs
--- a/test/Avro/Decode/RawBlocksSpec.hs
+++ b/test/Avro/Decode/RawBlocksSpec.hs
@@ -14,13 +14,14 @@
 import Data.Text                    (pack)
 import HaskellWorks.Hspec.Hedgehog
 import Hedgehog
-import Hedgehog.Range              (Range)
+import Hedgehog.Range               (Range)
 import Test.Hspec
 
-import qualified Hedgehog.Gen                as Gen
-import qualified Hedgehog.Range              as Range
+import qualified Hedgehog.Gen   as Gen
+import qualified Hedgehog.Range as Range
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Reduce duplication"  -}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Decode.RawBlocksSpec" $ do
diff --git a/test/Avro/Decode/RawValuesSpec.hs b/test/Avro/Decode/RawValuesSpec.hs
--- a/test/Avro/Decode/RawValuesSpec.hs
+++ b/test/Avro/Decode/RawValuesSpec.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications    #-}
+
 module Avro.Decode.RawValuesSpec
 where
 
@@ -15,10 +16,11 @@
 import Hedgehog.Range              (Range)
 import Test.Hspec
 
-import qualified Hedgehog.Gen                as Gen
-import qualified Hedgehog.Range              as Range
+import qualified Hedgehog.Gen   as Gen
+import qualified Hedgehog.Range as Range
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Reduce duplication"  -}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Decode.RawValuesSpec" $ do
diff --git a/test/Avro/DefaultsSpec.hs b/test/Avro/DefaultsSpec.hs
--- a/test/Avro/DefaultsSpec.hs
+++ b/test/Avro/DefaultsSpec.hs
@@ -16,7 +16,7 @@
 import Hedgehog
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.DefaultsSpec: Schema with named types" $ do
@@ -29,7 +29,7 @@
       defaults = fldDefault <$> fields msgSchema
     in defaults `shouldBe` [ Just $ DUnion (V.fromList [Null, String']) Null DNull
                            , Just $ DFixed fixedSchema "\0\42\255"
-                           , Just $ (DBytes Bytes') "\0\37\255"
+                           , Just $ DBytes Bytes' "\0\37\255"
                            ]
 
   it "should encode schema with default" $
diff --git a/test/Avro/EncodeRawSpec.hs b/test/Avro/EncodeRawSpec.hs
--- a/test/Avro/EncodeRawSpec.hs
+++ b/test/Avro/EncodeRawSpec.hs
@@ -8,7 +8,7 @@
 import           Data.Word
 import           Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 bitStringToWord8s :: String -> [Word8]
 bitStringToWord8s = reverse . map (toWord . reverse) . chunksOf 8 . reverse . toBinary
diff --git a/test/Avro/Encoding/ContainerSpec.hs b/test/Avro/Encoding/ContainerSpec.hs
--- a/test/Avro/Encoding/ContainerSpec.hs
+++ b/test/Avro/Encoding/ContainerSpec.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE DataKinds         #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TypeApplications  #-}
+
 module Avro.Encoding.ContainerSpec
 where
 
@@ -19,9 +19,8 @@
 import qualified Avro.Data.Endpoint as Endpoint
 import qualified Avro.Data.Unions   as Unions
 
-{-# ANN module ("HLint: ignore Redundant do"    :: String) #-}
-{-# ANN module ("HLint: ignore Redundant flip"  :: String) #-}
-
+{- HLINT ignore "Reduce duplication"  -}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Encoding.ContainerSpec" $ do
diff --git a/test/Avro/Encoding/DeconflictSpec.hs b/test/Avro/Encoding/DeconflictSpec.hs
--- a/test/Avro/Encoding/DeconflictSpec.hs
+++ b/test/Avro/Encoding/DeconflictSpec.hs
@@ -18,8 +18,8 @@
 import Hedgehog
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"    :: String) #-}
-{-# ANN module ("HLint: ignore Redundant flip"  :: String) #-}
+{- HLINT ignore "Reduce duplication"  -}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Encoding.DeconflictSpec" $ do
diff --git a/test/Avro/Encoding/LogicalTypesSpec.hs b/test/Avro/Encoding/LogicalTypesSpec.hs
--- a/test/Avro/Encoding/LogicalTypesSpec.hs
+++ b/test/Avro/Encoding/LogicalTypesSpec.hs
@@ -9,8 +9,8 @@
 import Hedgehog
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"    :: String) #-}
-{-# ANN module ("HLint: ignore Redundant flip"  :: String) #-}
+{- HLINT ignore "Reduce duplication"  -}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.Encoding.LogicalTypesSpec" $ do
diff --git a/test/Avro/JSONSpec.hs b/test/Avro/JSONSpec.hs
--- a/test/Avro/JSONSpec.hs
+++ b/test/Avro/JSONSpec.hs
@@ -31,13 +31,13 @@
 import System.Directory   (doesFileExist, getCurrentDirectory)
 import System.Environment (setEnv)
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvro "test/data/unions-no-namespace.avsc"
 
 spec :: Spec
 spec = describe "Avro.JSONSpec: JSON serialization/parsing" $ do
-  it "should pass" $ require $ withTests 1 $ property $ success
+  it "should pass" $ require $ withTests 1 $ property success
 
   -- it "should do roundtrip (enums)" $ require $ property $ do
   --   msg <- forAll enumWrapperGen
diff --git a/test/Avro/ManualSpec.hs b/test/Avro/ManualSpec.hs
--- a/test/Avro/ManualSpec.hs
+++ b/test/Avro/ManualSpec.hs
@@ -24,7 +24,7 @@
 import qualified Hedgehog.Range              as Range
 import           Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 data Person = Person
   { fullName :: Text
@@ -35,9 +35,9 @@
 schema'Person :: Schema
 schema'Person =
   Record "Person" []  Nothing
-    [ fld "fullName"  (String Nothing)                        Nothing
-    , fld "age"       (Int Nothing)                           Nothing
-    , fld "ssn"       (mkUnion $ Null :| [(String Nothing)])  Nothing
+    [ fld "fullName"  (String Nothing)                      Nothing
+    , fld "age"       (Int Nothing)                         Nothing
+    , fld "ssn"       (mkUnion $ Null :| [String Nothing])  Nothing
     ]
   where
      fld nm ty def = Field nm [] Nothing Nothing ty def
diff --git a/test/Avro/NamespaceSpec.hs b/test/Avro/NamespaceSpec.hs
--- a/test/Avro/NamespaceSpec.hs
+++ b/test/Avro/NamespaceSpec.hs
@@ -13,8 +13,7 @@
 import Paths_avro
 import Test.Hspec
 
-
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "NamespaceSpec.hs: namespace inference in Avro schemas" $ do
diff --git a/test/Avro/NormSchemaSpec.hs b/test/Avro/NormSchemaSpec.hs
--- a/test/Avro/NormSchemaSpec.hs
+++ b/test/Avro/NormSchemaSpec.hs
@@ -12,7 +12,7 @@
 
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.NormSchemaSpec" $ do
diff --git a/test/Avro/RecursiveSpec.hs b/test/Avro/RecursiveSpec.hs
--- a/test/Avro/RecursiveSpec.hs
+++ b/test/Avro/RecursiveSpec.hs
@@ -11,7 +11,7 @@
 import Hedgehog
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.RecursiveSpec" $ do
diff --git a/test/Avro/ReuseFixedSpec.hs b/test/Avro/ReuseFixedSpec.hs
--- a/test/Avro/ReuseFixedSpec.hs
+++ b/test/Avro/ReuseFixedSpec.hs
@@ -9,7 +9,7 @@
 import Avro.TestUtils (roundtrip)
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.ReuseFixedSpec" $ do
diff --git a/test/Avro/SchemaSpec.hs b/test/Avro/SchemaSpec.hs
--- a/test/Avro/SchemaSpec.hs
+++ b/test/Avro/SchemaSpec.hs
@@ -15,7 +15,7 @@
 
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.SchemaSpec" $ do
diff --git a/test/Avro/THEnumSpec.hs b/test/Avro/THEnumSpec.hs
--- a/test/Avro/THEnumSpec.hs
+++ b/test/Avro/THEnumSpec.hs
@@ -10,7 +10,8 @@
 
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
+
 deriveAvroWithOptions (defaultDeriveOptions { namespaceBehavior = HandleNamespaces }) "test/data/enums.avsc"
 
 spec :: Spec
diff --git a/test/Avro/THReusedSpec.hs b/test/Avro/THReusedSpec.hs
--- a/test/Avro/THReusedSpec.hs
+++ b/test/Avro/THReusedSpec.hs
@@ -10,7 +10,7 @@
 
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 deriveAvroWithOptions (defaultDeriveOptions { namespaceBehavior = HandleNamespaces }) "test/data/reused.avsc"
 
diff --git a/test/Avro/ToAvroSpec.hs b/test/Avro/ToAvroSpec.hs
--- a/test/Avro/ToAvroSpec.hs
+++ b/test/Avro/ToAvroSpec.hs
@@ -11,8 +11,7 @@
 import Hedgehog
 import Test.Hspec
 
-{-# ANN module ("HLint: ignore Redundant do"    :: String) #-}
-{-# ANN module ("HLint: ignore Redundant flip"  :: String) #-}
+{- HLINT ignore "Redundant do"        -}
 
 spec :: Spec
 spec = describe "Avro.ToAvroSpec" $ do
