- If you want to extract them out, it's safe and straightforward. Still a tedious refactor, but a safe tedious refactor. It's not any harder than injecting stuff up-front. Given that, why do the work now if it's not any harder to do later, and you may not need to do it?
- If you hardcode dependencies except for those you can't hardcode, that means that if you come across something which isn't hard coded, you know immediately there must be some reason it needs to be injected in! This makes reading code easier, since following this convention the code itself tells you how it's used, vs having to guess whether an injected dependency is actually necessary or whether it has just one instantiation and can be hardcoded
- You are already hardcoding all sorta of things anyway. The `Seq` object? The `String` type? These, and other things, can be injected in as params or type-params if we really want to. The question is then when do you stop and draw the line? You obviously can't inject everything. "Only inject stuff that needs to be injected" provides a clear, unambiguous guideline that applies equally to dependencies on your code, on the std lib, or on third party libraries
Thanks for your input!
Related in that you mentioned dependency injection, unrelated in that it is not directly relevant to the content of Strategic Scala Style. (maybe of interest to some though).
0 - https://yow.eventer.com/yow-2012-1012/lambda-the-ultimate-de...
Great write-up regarding good software engineering practices in general, and ones applicable to Scala development specifically.
Two things I submit to be clarified/added to Strategic Scala Style are:
1 - Explicitly declare the return type of all public methods.
Doing so ensures that type inference does not propagate implementation types to the caller (often eliminating compilation errors) and, in my experience, greatly assists in reduction of errors when working with higher-kinded types. IMHO, it also assists in understanding a system due to an explicit contract being expressed.
2 - As "Joe Clueless" wrote in the comments, why isn't Either presented as a viable alternative to Option?
Again, IMHO, while Option is an exceptionally useful type, when indicating errors at the "public API level" it proves to be insufficient. The distjoint union type Either allows a collaboration to be both explicit that a failure may occur as well as indicate what the failure was (if any).
Hopefully these comments help and, again, kudos to a great write-up.
+1
This is very helpful for quickly scanning code.
>Again, IMHO, while Option is an exceptionally useful type, when indicating errors at the "public API level" it proves to be insufficient.
Agreed. Either, or even better, \/ (Scalaz either/disjunction) is much easier to work with and more expressive.
> Agreed. Either, or even better, \/ (Scalaz either/disjunction) is much easier to work with and more expressive.
I, too, recommend using the Scalaz \/[0] Either type as it is "right leaning" and lends itself quite nicely to processing due to it being both a model of Bifunctor[1] (making handling either a success or failure situation quite clean) and contributing nicely to defining an EitherT monad transformer capable of abstracting both latency (the Future part) and errors (the \/ part).
For example, I often have the following defined in projects:
type FutureEither[+T] = EitherT[Future, DomainError, T]
Where "DomainError" is a top-level type representing an error encountered during processing.All this adds up to being able to work with "happy path" logic, deferring error handling until it can be handled/reported and network request/response latency absorbed until it becomes an error (addressed as any other error would be).
0 - https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/...
1 - https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/...
As to Either, I didn't mention it because I don't use it much, and don't see many other people using it either. Sure you can use it and it'll work, but it's not the style I use or the style I see most open source libraries using.
As for Scalaz, yeah \/ is great, or cats' Xor. But this doc is all about Vanilla Scala: for every library out there, they will have their own best practices, that are totally uninteresting to people not using hat library. If someone wants to write similar documents for Scalaz, Cats, Akka, Play, Finagle, Play, they would each probably be just as long as this one, and probably just as valuable!
IMHO your scope is spot on for Vanilla Scala and will help many.
Regarding the similar documents shout-out, here's one for Scalaz which I found very well written:
http://eed3si9n.com/learning-scalaz/index.html
Perhaps others know of write-ups similar to yours and this one for some of the others you mentioned. Could be interesting to compile them into a "see also" kind of thing.
What I'd really like is a simple type union syntax, so I could union the happy path result with any number of failure modes, where there isn't necessarily a common supertype for anything.
I frequently see Either abused to represent the lack of Union Types. But then I also see it used for errors. And it's not really a perfect fit for either (no pun intended).
Every (a non-Empty List) is also nice. I like Scalactic. It adds just a couple of small useful things. Very lightweight.
Option (Some or None), Or (Good or Bad) and Try (Success or Failure[T <: Throwable]) cover the bases for me.
Just in case others were unaware of scalactic. (sister library to scalatest, so if you're already using scalatest, you're already using scalactic under the covers I believe)
If all you need is represent an optional value, why use `Either`, which needs a second type parameter representing the failure? If you don't care about what caused the failure (because there was no failure, an absence of value is a valid result), no need to represent it.
Besides, these two classes still represent fundamentally different concepts and they are not interchangeable at all.
Sorry for any confusion I may have introduced when re-stating the question originally posed by "Joe Clueless" in the comments section.
Since you're here, on another subject, I've been toying with using Scala.js with Duktape to integrate Scala into a C++ project as a scripting language. Have you seen or heard anyone who has successfully done this or any pointers you may have?
p.s. Thank you for all you've contributed to the Scala community. Your posts are always enlightening and your projects incredibly forward thinking!
You could try learning from a book or a course, but personally I've never found a better way of learning "what I need to learn for X" than trying to do X and then googling all the things I don't know.
Sure, you'll forget a whole bunch of that stuff, but if it's at all important you'll find yourself re-learning it again and again until it sticks.