- A getOperation.. this can return an option of v
- A writeOperation(key, value, modeOfWriting) … this can return a
Result
. The Result should encapsulate the actual return value and the mode. TheMode
can beOverwrite
(which can beReplaced
orNew
orFailed
), Insert (which can beNew
orFailed
) orReplace
(which can be Wrote or Failed). Feel free to represent this in any way which is type safe. - A deleteOperation returning a unit.
- The
Result
also hasFaiureFallBackOperations
orIfSuccess
encoded in as well. This may or may not be used by the clients usingDbOperation
. - A readAll returning a
Page
, representing alist of value
and thenext key
.
// Time to scrap Future! | |
// The **push** nature of scala.concurrent.Future! | |
val s = Future { (0 to 10).map(t => Thread.sleep(2000); scala.util.Random.nextInt(1 + t)) } | |
s.foreach(println(_)) | |
// It will take 20 seconds to print out Vector(0, 0, 0, 1, 0, 4, 1, 3, 5, 9, 10) | |
s.foreach(println(_)) | |
// This time the same line of code behaves differently. | |
// It prints out without delay and hence broke the substitution principle. |
Type parameterisation is done for us to later discover, for instance, that we could test our CRUD service layer with all combinations of errors a database can produce as a single test case. How many applications do that?...
Any implementations should go with property based tests/laws. Else it is fairly hard to convince even ourselves why not a Java/Python/any imperative alternate. Let's don't be biased for no reason.
It is easier to convince that concurrency management and related library development with Scala (well, FP) is better as we love compositions than call backs and waiting. But application level FP usage is justified, for instance, when you are able to say “Let me push to master, coz it will work for sure”. That confidence comes easily with type driven development
and laws
.
// The code base below shows how horrible it is to use AtomicReference | |
// (Yes, we are talking about concurrency) in the world of mutation. | |
// This should be one of your answer to why you hate mutation for the sake of performance - | |
// The gist is a simple example to ABA problem. | |
// While the problem sounds ridiculously easy, the gist show how can it happen in a real world, | |
// and how on earth can it lead to program error. | |
@ val s = new AtomicLong(0) | |
s: AtomicLong = 0 |
import java.time.Instant | |
import java.util.concurrent.atomic.{AtomicReference, AtomicReferenceArray} | |
import monix.eval.Task | |
import monix.execution.atomic.AtomicLong | |
import monix.reactive.{Consumer, Observable} | |
import monix.reactive.observables.ObservableLike.Transformer | |
import scala.annotation.tailrec |
package com.thaj.functionalprogramming.exercises.part4 | |
import scalaz.{ Scalaz, _ } | |
import Scalaz._ | |
// Thanks to https://underscore.io/blog/posts/2017/03/29/free-inject.html | |
object CombineFreeInScalaz { | |
sealed trait Logging[A] | |
case class Info(s: String) extends Logging[Unit] |
package com.telstra.dxhub.productmapper | |
import shapeless.{::, Generic, HList, HNil, Poly, Poly1} | |
import shapeless.PolyDefns.{Case, Case0} | |
import shapeless.ops.hlist.Mapper | |
trait ProductMapper[A, B, P] { | |
def apply(a: A): B | |
} |
@ //This is ammonite configured for shapeless | |
@ object NewNumber extends Tagger[Int] | |
defined object NewNumber | |
@ type NewNumber = NewNumber.Type | |
defined type NewNumber | |
@ case class World(name: Name, exchangId: ExchangeId, newNumber: NewNumber) | |
defined class World |
@ //This is ammonite configured for shapeless | |
@ implicitly[Validation[SuperExchange]].validate(SuperExchange(ExchangeId("id"), Name("name"))) | |
res48: ValidationNel[ValidationError, SuperExchange] = Success(SuperExchange("id", "name")) |