6 ms·
Neat to see this appear here. I wrote this. Ask me anything
by lihaoyi 11y ago
Neat to see this appear here. I wrote this. Ask me anything
- kailuowang 11y agoNot relevant to your post, but I kept getting asked by data engineers who are interested picking up scala (thanks to spark): how shall I learn scala? Do you happen to have any advice for them?
- lihaoyi 11y agoFind something you want to do, try to do it, find out what you don't know, and learn it. 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.
- audi100quattro 11y agoScala by example and the coursera courses by Martin Odersky have helped me, but like Li said, there is no substitute to having something in mind and getting your hands dirty using Akka, Play or Spark and Googling what you don't know. http://www.scala-lang.org/docu/files/ScalaByExample.pdf http://www.scala-lang.org/docu/files/ScalaByExample.pdf
- Negative1 11y agoNo specific questions about your blog post but want to echo the sentiment that Scala is incredibly easy for refactoring. With Python (or even C++) it can be quite the chore, but as you said, building simple and using the compiler to guide you has great benefits. I'm currently going through the process right now with an AWS database backup utility I've been writing. 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!
- AdieuToLogic 11y agoHi Haoyi, 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.
- runT1ME 11y ago> Explicitly declare the return type of all public methods. +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.
- AdieuToLogic 11y ago> >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. 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/main/scala/scalaz/Either.scala 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/main/scala/scalaz/Bifunctor.scala https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/...
- mhotchen 11y agoComing from an OO background the idea of hard-coding dependencies makes my palms sweat a bit. Your example is pretty simple and I agree with it but for objects/packages that are "reaching out" to the wider system rather than staying in their bounds do you not think this principle could create a loosely cohesive system? I would say that dependency injection isn't just about swapping behaviour, but it's about cohesion and bounded contexts and all that stuff that makes systems easier to reason about.
- lihaoyi 11y agoi say "hardcode dependencies" for three reasons: - 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
- mhotchen 11y agoYeah that makes a lot of sense. I think points two and three would be beneficial to the article, because point one by itself could be said of a lot of things (eg. large methods and classes, or deeply nested and complex algorithms). Thanks for your input!
- AdieuToLogic 11y agoOn a semi-related note, here[0] is a talk given by a gentleman named Runar Bjarnason discussing a Dependency Injection technique in Scala. 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-dependency-injection-framework-by-runar-bjarnason-1277 https://yow.eventer.com/yow-2012-1012/lambda-the-ultimate-de...