{"action":"created","comment":{"url":"https://api.github.com/repos/netvl/scala-guidelines/pulls/comments/70979117","id":70979117,"diff_hunk":"@@ -0,0 +1,1432 @@\n+# Introduction\n+\n+Scala language has lots of features over the baseline Java, and many of them provide a quite significant boost in readability and correctness of the code, as well as productivity of a developer. However, many of these features, and many libraries which are or are not based on these features require considerable experience to be used correctly and actually hinder readability of the code, especially for people who are unfamiliar with the concepts used in these libraries, with the code base, or with the whole JVM/Java/Scala ecosystem in general.\n+\n+The intention of this document is to provide a general overview of Scala usage practices which should be employed to keep the code base approachable, understandable and maintainable, while not hindering the developers productivity. Note that some of these practices are enforced automatically with the code style analyzers and linters, and therefore their violation will result in a failed build. Most, however, are enforced through the code review process. Therefore, it is absolutely necessary for the reviewers to understand this document by heart and apply it rigorously. To help with this task, a dedicated section at the end of the document serves as a handbook for reviewers, providing a list of most important things to look for during the code review.\n+\n+This document is heavily based on the following existing Scala guidelines:\n+\n+* Twitter's Effective Scala: https://twitter.github.io/effectivescala/\n+* Databricks Scala Guide: https://github.com/databricks/scala-style-guide\n+* Scala Best Practices: https://github.com/alexandru/scala-best-practices\n+\n+as well as our own experience in writing Scala code.\n+\n+This document will be updated in the future to include things we will encounter when dealing with new code contributions.\n+\n+# Table of contents\n+\n+[TOC]\n+\n+# General code style (TODO?)\n+\n+As a general rule, constantly monitor warnings and other notices which your IDE shows you. IntelliJ IDEA in particular has clever analysis features which are very helpful to avoid many mistakes in the code style. If you use IDEA to make commits, enable \"Before commit / Perform code analysis\" option in its commit window - it will display all errors and warnings it sees in the code you're about to commit.\n+\n+## Formatting and whitespace\n+\n+Formatting suggested by the configured IDEA should be preferred. If in doubt, use the \"Reformat code\" action.\n+\n+Lines should be indented with two spaces. Lines longer than 120 characters in length should be avoided.\n+\n+## Naming\n+\n+### Length of names\n+\n+Follow the rule \"longer names for larger scopes, shorter names for smaller scopes\". One-letter names for numeric loops indices are acceptable, same names for most of local variables and pattern variables are not.\n+\n+### Apostrophes\n+\n+Avoid using \\`s to overload reserved names. Use of apostrophes in pattern matching for equality checking, on the other hand, is acceptable:\n+\n+```scala\n+val name = \"hello\"\n+\n+x match {\n+  case SomeClass(`name`) => ...\n+}\n+```\n+\n+### Constant names\n+\n+Constants must always follow the `PascalCase` naming rule, according to the default style used in Scala community. Do not use `CAPITAL_SNAKE_CASE` or `camelCase` for constant names.\n+\n+Constants must always be defined in objects. If a constant is only used in one class, then it should be defined in its companion object. If a constant is used in multiple classes, it should be defined in some common object.\n+\n+Constants must not be defined in package objects.\n+\n+### Getters\n+\n+Do not prefix getters with `get`, just name the getter after the thing it retrieves:\n+\n+```scala\n+trait Nameable {\n+  def name: String\n+}\n+```\n+\n+### Names shadowing\n+\n+Avoid clashes of the names with pattern matching, e.g. don't do this:\n+\n+```scala\n+case class User(...)\n+case class Organization(owner: User)\n+\n+val user = User(...)\n+...\n+organization match {\n+  case Organization(user) => ...  // user clashes with the above val\n+}\n+```\n+\n+do e.g. this:\n+\n+```scala\n+organization match {\n+  case Organization(owner) => ...\n+}\n+```\n+\n+Names shadowing can be resolved by the IDEs, but nevertheless is a bad idea because it is very easy to mistake one variable for another. Use more appropriate names for each variable and pattern.\n+\n+## Imports\n+\n+### Imports order\n+\n+Use the IDEA imports optimizer to sort imports. **TODO: add the snippet with the imports configuration** Source code files should not contain unused imports.\n+\n+### Relative imports\n+\n+Always use absolute imports; IDEA code style configuration enforces this. Relative imports almost always decrease the readability.\n+\n+### Imports location\n+\n+Always put imports at the top of the file instead of nested scopes. In other words, imports must always be grouped together in one place.\n+\n+## Braces\n+\n+### Definitions\n+\n+Avoid using braces for simple expressions; write this:\n+\n+```scala\n+def square(x: Int) = x * x\n+```\n+\n+but not this:\n+\n+```scala\n+def square(x: Int) = {\n+  x * x\n+}\n+```\n+\n+even though it may be tempting to distinguish the method body syntactically. The first alternative has less clutter and is easier to read. Avoid syntactical ceremony unless it clarifies.\n+\n+### Scoping and blocks\n+\n+It is acceptable to use braces in order to limit the namespace pollution, but this should almost always be used only when the result of the block is assigned to another variable:\n+\n+```scala\n+val someValue = {\n+  val localVariable = ...\n+  ...\n+}\n+```\n+\n+Moreover, using blocks to put complex expressions in other expressions, most notable function calls, hinders readability in a really bad way and should be avoided:\n+\n+```scala\n+// bad\n+someFunction(arg1, arg2, {\n+  ...more code...\n+}, arg4)\n+\n+// good\n+val arg3 = {\n+  ...more code...\n+}\n+someFunction(arg1, arg2, arg3, arg4)\n+```\n+\n+## Comments\n+\n+Use Scaladoc to provide API documentation. Use the following style:\n+\n+```scala\n+/**\n+ * ServiceBuilder builds services \n+ * ...\n+ */\n+```\n+\n+but not the standard Scaladoc style:\n+\n+```scala\n+/** ServiceBuilder builds services\n+  * ...\n+  */\n+```\n+\n+Public API must always be documented with Scaladoc.\n+\n+Write comments to clarify parts of logic which are not obvious, but *only* when it is absolutely impossible to rewrite the logic to be obvious in the first place. In general, try follow the rule \"readable code comments itself\".\n+\n+`TODO:`-like comments are acceptable when they are really necessary but should not be overused.\n+\n+# Type system\n+\n+The primary objective of a powerful static type system is to reduce the number of bugs and other programming errors. Moreover, static type system often gives benefits in code readability and navigation (with the help of IDEs). However, overusing the type system in Scala leads to code which is very hard to understand. Therefore, most of the advanced techniques which are possible with the Scala type system must be avoided.\n+\n+## Return type annotations\n+\n+Scala allows one to omit return type annotations on `def`s. However, these annotations increase readability and help to avoid many issues with the type system, therefore all public-facing methods must have return types:\n+\n+```scala\n+trait PublicInterface {\n+  def computeValue(input: String): AnotherEntity\n+}\n+```\n+\n+This includes overrides in the classes extending the supertype:\n+\n+```scala\n+class PublicInterfaceImpl extends PublicInterface {\n+  override def computeValue(input: String): AnotherEntity = {\n+    ...\n+  }\n+}\n+```\n+\n+It is acceptable to omit return types for *short* local functions, but only when it is very clear what the return type is, for example:\n+\n+```scala\n+def updatedUser(user: User) = user.copy(parameter = anotherValue)\n+```\n+\n+Here it is clear that the returned value is `User`, and the function itself is short, so it is okay to omit the return type.\n+\n+## Structural typing\n+\n+Scala allows structural typing based on reflection, i.e. it is possible to define the interface which a variable should have directly as type:\n+\n+```scala\n+case class Something(id: String)\n+\n+val x: { def id: String } = Something(\"abcde\")\n+```\n+\n+Structural typing must be avoided in all its forms because it hurts both runtime performance and code readability and maintainability.\n+\n+## Generics and variance\n+\n+The necessity to create types with generic parameters should be very rare, however, if there is a need to create one, then their type should be properly annotated with variance.\n+\n+There is a general rule about that: if a type only \"produces\" values of the generic type, i.e. when this type is present only in return positions in all methods in the class, then this generic parameter must be marked as covariant:\n+\n+```scala\n+trait Collection[+T] {\n+  def head: T\n+}\n+```\n+\n+If a type only \"consumes\" values of the generic type, i.e. when this type is present only in parameters positions in all methods in the class, then this generic parameter must be marked as contravariant:\n+\n+```scala\n+trait Comparator[-T] {\n+  def compare(left: T, right: T): Int\n+}\n+```\n+\n+If a type both \"produces\" and \"consumes\" values of the generic type, then this generic type must not be marked with any markers and therefore be invariant:\n+\n+```scala\n+trait MutableBuffer[T] {\n+  def head: T\n+  def push(value: T)\n+}\n+```\n+\n+Using appropriate variance increases the maintainability of the code, like any other contract between types.\n+\n+## Higher-kinded types\n+\n+Higher-kinded types represent an ability to abstract over type constructors, as opposed to abstracting over concrete types. For example, regular collections are examples of types of the first kind:\n+\n+```scala\n+class ArrayBuffer[T] {\n+  private val data: Array[T] = ...\n+  ...\n+}\n+```\n+\n+Here `T` is a concrete type - it may be `Int`, `String`, `Vector[Double]`, or whatever else.\n+\n+The following definition, however, is a type of the second kind:\n+\n+```scala\n+trait Functor[F[_]] {\n+  def map[A, B](f: A => B): F[A] => F[B]\n+}\n+```\n+\n+Note how exactly the `F` type parameter of the trait is defined and the fact that it is used with *different* type arguments inside the trait body. This trait accepts not a concrete type, but a *type constructor* - something which can be applied to a concrete type to get another concrete type.\n+\n+Higher-kinded types, that is, an ability to define traits like the `Functor` above, are an extremely powerful feature which allows expression of many complex abstractions, however, these abstractions are objectively hard to understand for people who never worked with them before. Therefore, declaring custom higher-kinded types is forbidden. Not many languages which have generics also have the support for higher-kinded types, and they do nicely without them, so there are always ways to solve the problem at hand without HKTs.\n+\n+Unfortunately, higher-kinded types are sometimes used in libraries. One of the most prominent examples are the standard Scala collections. Usually you won't need to even know about HKTs to work with Scala collections, which is a good thing; however, if you intend to extend the collections library in any way, e.g. by adding extension methods to collections, the necessity to work with higher-kinded types should taken into account. Thus it is not forbidden to use higher-kinded types, but always try to think about whether it is possible to solve the problem you're working on without relying on them.\n+\n+## Abstract (associated) types\n+\n+Scala allows one to define abstract types in classes which then could be overridden in subclasses:\n+\n+```scala\n+trait Container {\n+  type Item\n+}\n+\n+class IntContainer extends Container {\n+  override type Item = Int\n+}\n+```\n+\n+This feature is related to path-dependent types and very often leads to very confusing code, and therefore must be avoided at all costs.\n+\n+Note that defining type aliases (which is also done with the `type` keyword) is perfectly fine; it's abstract types which are overridden with a concrete type are forbidden.\n+\n+## Path-dependent types\n+\n+Type members defined in classes are resolved relatively to the variable which contains an instance of such class:\n+\n+```scala\n+class Container {\n+  type Item = Int\n+  val n: Item = 10\n+}\n+\n+val x = new Container\n+\n+val c1 = Vector[x.Item]()\n+```\n+\n+In other words, it is possible for types to depend on the value, or, more correctly, on the \"path\" to the type, expressed in terms of values.\n+\n+This is one of the most confusing features of Scala type system, and while it can lead to more type safe code when used correctly, it is very difficult to actually used it correctly, and it may produce quite incomprehensible errors.\n+\n+Therefore, using path-dependent types is forbidden. There is almost always a better way to do something than  relying on them.\n+\n+## Type aliases\n+\n+Defining type aliases for complex types is encouraged. However, self-explanatory types need not to be aliased. The following is a bad example:\n+\n+```scala\n+type IntMaker = () => Int\n+```\n+\n+Type aliases should be used instead of subtyping, when this subclassing does not actually extend the original type.\n+\n+```scala\n+// don't do this\n+trait SocketFactory extends (SocketAddress => Socket)\n+\n+// do this\n+type SocketFactory = SocketAddress => Socket\n+```\n+\n+Type aliases are best defined in the companion objects of the classes they are used in, but if a particular type alias is exposed as a part of an API or otherwise is used in common by many other modules, it makes sense to put it into the package object.\n+\n+## `Any`, `AnyRef` and `AnyVal`\n+\n+`Any` and `AnyRef` represent the top-level types, for all values, for all references and for all non-references, respectively. Because of the subtyping, every value may be stored in a variable typed `Any`. Therefore, `Any` can be thought as an \"escape hatch\" from the type system, and so should not be used in regular code.\n+\n+If you need to encode values which may be of a finite set of different types, consider writing an ADT which encodes these types as its variants:\n+\n+```scala\n+sealed trait Variant\n+object Variant {\n+  case class Int(value: scala.Int) extends Variant\n+  case class String(value: java.lang.String) extends Variant\n+  // etc.\n+}\n+```\n+\n+## `isInstanceOf`, `asInstanceOf`\n+\n+These methods are often used in conjunction with `Any*` types, and thus should be avoided in the regular code. If you do need to check a runtime type of a variable, use pattern matching instead:\n+\n+```scala\n+value match {\n+  case x: SomeType => ...\n+  case _ => ...\n+}\n+```\n+\n+One of the most common applications of this pattern are algebraic data types which are described in their own section.\n+\n+# Language features\n+\n+## Implicits\n+\n+Implicits comprise a very powerful part of the Scala language, however (or even therefore) they often lead to code which is very hard to understand if they are overused.\n+\n+Implicits as a feature are used pervasively for many tasks across the entire Scala ecosystem, so it unfeasible to completely disallow their usage. In particular, they solve both the expression problem (adding new methods to existing types) and the cross-cutting concerns problem (using a single globally configured value in different places of code) transparently. However, they must be used sparingly, and only when their usage is motivated by a significant increase in readability or by the necessity to integrate with other libraries.\n+\n+The general rule is as follows (quoting Twitter's Effective Scala):\n+\n+> If you do find yourself using implicits, always ask yourself if there is a way to achieve the same thing without their help.\n+\n+### Implicit conversions\n+\n+Implicit conversions are declared as functions which accept a value and return a value of a different type. These functions are then used by the compiler to implicitly convert the original value if necessary, e.g. when it is passed to somewhere when the target type is expected or when a method is called which is not available on the source type but available on the return type:\n+\n+```scala\n+implicit def intAsString(x: Int): String = x.toString\n+\n+x.length  // equivalent to x.toString.length\n+```\n+\n+Implicit conversions are absolutely forbidden to be declared, and their usage from the third-party libraries must be avoided at all costs. Fortunately, the Scala community at large considers implicit conversions as an anti-feature and therefore most popular libraries do not depend on it. One of the notable examples of implicit conversions is the built-in Scala-to-Java collection conversions:\n+\n+```scala\n+import scala.collection.JavaConversions._\n+\n+val s: Vector[Int] = Vector(1, 2, 3)\n+val x: java.util.List[Int] = s  // gets converted automatically\n+```\n+\n+Using `JavaConversions` (and additionally `wrapAsJava`, `wrapAsScala` and `wrapAll`) is strictly forbidden; in case if such conversions are necessary, `decoratedAsJava`, `decorateAsScala` or `decorateAll` should be used:\n+\n+```scala\n+import scala.collection.convert.decorateAsJava._\n+\n+val s: Vector[Int] = Vector(1, 2, 3)\n+val x: java.util.List[Int] = s.asJava\n+```\n+\n+### The expression problem, extension methods\n+\n+[Expression problem](https://en.wikipedia.org/wiki/Expression_problem) is basically a task of adding new operations to an already defined type. It is well known that most of the \"old\" static languages, like C, C++ and Java, do not have any kind of solution for it. In most dynamic languages this is not a problem due to dynamic typing and monkey patching, but static languages also have their own solutions. For example, C# and Kotlin have extension methods, while Haskell and Rust have type classes (called traits in the latter). Scala solution for the expression problem are methods injected through implicits.\n+\n+Modern IDEs, in particular, IntelliJ IDEA, are able to understand most if not all commonly used implicits usage scenarios: in particular, they are able to highlight methods added through implicit classes and show implicit parameters of a method call, and allow to navigate to the definition of these methods. Therefore, using implicits for simple tasks, like adding new methods to existing types, is not forbidden:\n+\n+```scala\n+implicit class ArrayOps[A](val arr: Array[A]) extends AnyVal {\n+  def firstTwoOpt: Option[(A, A)] = if (arr.length >= 2) Some((arr(0), arr(1))) else None\n+}\n+```\n+\n+Note, however, that for this to be acceptable, such extension must be motivated by a significant increase of readability. In particular, this is justified when the newly added operation is used very often in some part of code. If this operation is defined as a regular function, it would require calling it with the function syntax instead of the method syntax:\n+\n+```scala\n+arr.firstTwoOpt\n+// vs\n+firstTwoOpt(arr)\n+```\n+\n+The function syntax requires parentheses, and when there are many calls of this function or if they are present in some complex expression which already has parentheses, it hurts readability. Extension methods, therefore, may be used if they help to reduce the noise.\n+\n+Extension methods must only be defined with an `implicit class` declaration, never via an `implicit def` conversion (see the above section). If possible, such `implicit class` must be defined in some object (including package objects) and extend `AnyVal` in order to avoid performance penalties of boxing.  It makes sense to add such operations to some common internal utilities library, and putting them *not* there should be avoided.\n+\n+### Implicit arguments\n+\n+Implicit arguments are used quite frequently by concurrency and serialization libraries in order to pass some auxiliary values around without them unnecessarily cluttering the code. Examples of such libraries are those using implicits to define class serializers (most JSON libraries in Scala do that) and passing around `ExecutionContext` with `Future`s.\n+\n+IDEs, in particular, IntelliJ IDEA, are quite capable of showing which implicit values are used in the particular method invocation, so understanding the code when they are used is not a hard problem. Thus, it is allowed to declare implicit arguments, especially when integrating with libraries mentioned above:\n+\n+```scala\n+// here both query() and map() calls accept the execution context implicitly\n+def load(id: String)(implicit ec: ExecutionContext): Future[SomeObject] =\n+  remoteApi.query(id).map(convertFromJson)\n+```\n+\n+However, it is almost never necessary to use implicit parameters of the types defined in the custom code base. Oftentimes this is done to \"simplify\" the code which eventually results in code which is messy and hard to read. Therefore, using implicit parameters for custom types unrelated to other libraries should be avoided.\n+\n+When interacting with the third-party libraries, it is sometimes necessary to define new implicit objects. The most prominent example is defining serializers for custom types. Definition of these implicits must be as contained as possible. Ideally a set of such definitions which are related in some way should be grouped together in one object, and this object should be imported when these implicits are needed:\n+\n+```scala\n+object ModelJsonFormatters {\n+  implicit val userFormat = Json.format[User]\n+  implicit val serviceFormat = Json.format[Service]\n+  implicit val whateverFormat = Json.format[Whatever]\n+}\n+\n+// at the use site\n+import some.pkg.ModelJsonFormatters._\n+\n+val jsonData = Json.toJson(Whatever(...))\n+```\n+\n+Naturally, using them must not contradict the rules about imports as they are defined above.\n+\n+As a final note, implicits are sometimes feared because they are used in complex libraries like scalaz. However, these libraries actually provide *concepts* which are hard to understand without prior experience; implicits only allow these libraries not to look absolutely horrible, and their absence from there would not make things better. This is the reason why usage of implicits is allowed: if used correctly (according to the guidelines presented above), they lead to much clearer code. If they are used together with a library which itself is very complex, they make things worse. The solution is to avoid using such libraries but not implicits; more on this below.\n+\n+## `override` modifier\n+\n+Scala requires `override` modifiers on items which override items with the same defined in the parent class, but it does not require it if these parent items are `abstract`:\n+\n+```scala\n+abstract class Root {\n+  def x: Int = 10\n+  abstract def y: Int\n+}\n+\n+class Child extends Root {\n+  override def x: Int = 12\n+  def y: Int = 42\n+}\n+```\n+\n+However, you should always use `override` modifier even for implementing abstract methods. This makes the fact that the item actually \"comes\" from a parent class obvious and it allows accidental non-overrides, for example, as a side effect of refactoring, to be caught during compilation easily.\n+\n+Note that you must use the `override` modifier even if you define the overriding field as a part of constructor arguments declaration:\n+\n+```scala\n+trait Entity {\n+  def id: String\n+}\n+\n+case class User(override val id: String) extends Entity\n+```\n+\n+## `abstract override` modifier\n+\n+Scala allows to \"incrementally\" extend a root trait, delegating to linear supertypes in a sequential manner. One of the most common usages of such feature is to create a collection of some items provided by separate trait implementations. This can be used, for example, to implement some kind of module system:\n+\n+```scala\n+trait Modules {\n+  def modules: Vector[Module]\n+}\n+\n+trait EmptyModules extends Modules {\n+  override def modules: Vector[Module] =\n+    Vector.empty\n+}\n+\n+trait PluginAModules extends Modules {\n+  abstract override def modules: Vector[Module] =\n+    super.modules :+ pluginAModule\n+}\n+\n+trait PluginBModules extends Modules {\n+  abstract override def modules: Vector[Module] =\n+    super.modules ++ Vector(pluginBFirstModule, pluginBSecondModule)\n+}\n+\n+class FinalModules\n+  extends EmptyModules\n+  with PluginAModules\n+  with PluginBModules\n+\n+println(new FinalModules().modules)  // prints Vector(pluginAModule, pluginBFirstModule, pluginBSecondModule)\n+```\n+\n+Another use of `abstract override` is to implement static chain of responsibility pattern, when all chain elements are compiled statically.\n+\n+`abstract override` is difficult to get right, and it is extremely confusing because it is often very hard to understand in which order traits methods are called. For this reason using `abstract override` is forbidden. There are almost always better ways to do the same thing.\n+\n+## Pattern matching\n+\n+Pattern matching is used everywhere in Scala.  Pattern matching combines conditional execution, destructuring and casting in one construct. It is one of the tools which are able to increase both clarity and safety of the code at the same time.\n+\n+When you pattern match on an ADT, prefer extracting values instead of accessing them with the method notation. In other words, write this:\n+\n+```scala\n+animal match {\n+  case Dog(name) => s\"A dog named $name\"\n+  case other => \"Someone else\"\n+}\n+```\n+\n+instead of this:\n+\n+```scala\n+animal match {\n+  case dog: Dog => s\"A dog named ${dog.name}\"\n+  case other => \"Someone else\"\n+}\n+```\n+\n+However, if a case class contains lots of fields, and you only need a handful of them, use the latter syntax because it would make the code less cluttered, and it would be harder to make a mistake when selecting a field to extract:\n+\n+```scala\n+component match {\n+  case Composite(_, _, _, _, children, _, _) =>\n+    processComponents(children)\n+  case _ => ...\n+}\n+```\n+\n+versus\n+\n+```scala\n+component match {\n+  case composite: Composite =>\n+    processComponents(composite.children)\n+  case _ => ...\n+}\n+```\n+\n+### `unapply` methods\n+\n+Scala allows to define a special method on a object called `unapply`. Objects with such methods can be used in the patterns to extract values using this method:\n+\n+```scala\n+case class Reference(entity: String, parameter: String) {\n+  override def toString: String = s\"$entity.$parameter\"\n+}\n+\n+object Reference {\n+  def fromString(s: String): Option[Reference] = s.split(\".\", 2) match {\n+    case Array(entity, parameter) => Some(Reference(entity, parameter))\n+    case _ => None\n+  }\n+}\n+\n+object ReferenceString {\n+  def unapply(s: String): Option[Reference] = Reference.fromString(s)\n+}\n+\n+someString match {\n+  case ReferenceString(Reference(_, parameter)) =>\n+    println(\"Parameter: $parameter\")\n+  case _ => ...\n+}\n+```\n+\n+It is hard to remember how `unapply` methods should be defined, and their overuse makes the code less readable, so they should not be used unless they significantly improve readability, e.g. when their functionality is used in many places in the code base.\n+\n+`unapply` methods must never be defined in regular classes, only in objects.\n+\n+## Multiple parameter lists\n+\n+Scala allows defining multiple parameter lists on methods and classes:\n+\n+```scala\n+def compare(x: Int)(y: Int): Int = x - y\n+\n+case class User(name: String, password: String)(secret: String)\n+```\n+\n+This feature affects type inference across parameters list and in the case of case classes it excludes all members of the non-first parameter lists from the `equals`, `hashCode` and `unapply` implementations.\n+\n+The latter point especially very often causes code which relies on multiple parameter lists to be confusing. Therefore, using them in general is forbidden.\n+\n+There are two use cases for which multiple parameters lists are allowed. The first one is definition of implicit arguments (see the respective section above):\n+\n+```scala\n+def doSomeWork(arg: String)(implicit ec: ExecutionContext) = ...\n+```\n+\n+The second one is when the second parameter list is used to accept a single functional value:\n+\n+```scala\n+def run(x: Int)(f: Int => String): String = f(x)\n+\n+run(10) { x => x.toString }\n+```\n+\n+Multiple parameter lists here allow using more concise syntax for passing an anonymous function which increases readability. That said, the need to declare such functions in itself should be rare, because of the rule against DSLs.\n+\n+The second use case, however, does not extend to multiple parameter lists which accept functions; in other words, something like the following is not allowed:\n+\n+```scala\n+def computeAnswer(onComplete: Int => Unit)\n+                 (onFailure: Throwable => Unit) = ...\n+\n+computeAnswer { x => println(x) } { e => e.printStackTrace() }\n+```\n+\n+If you do need to create a function which, for example, accepts multiple callbacks, use named parameters instead:\n+\n+```scala\n+def computeAnswer(onComplete: Int => Unit,\n+                  onFailure: Throwable => Unit) = ...\n+\n+run(\n+  onComplete = { x => println(x) },\n+  onFailure = { e => e.printStackTrace }\n+)\n+```\n+\n+## Symbolic methods and infix and postfix notation\n+\n+Scala allows to define methods which consist of symbols instead of regular letters. Combined with  the ability to call any method with the infix notation this allows one to define custom operators:\n+\n+```scala\n+class Connectable {\n+  def =+~>(other: Connectable): Connectable = ...\n+}\n+\n+val x = new Connectable\n+val y = new Connectable\n+x =+~> y\n+```\n+\n+Symbolic method names do not convey what they do, and with the exception of regular well-known symbols (mathematical operations, `++`/`--` on collections, boolean operators, negation, etc.) tend to be obscure by themselves: `a =+~> x` could mean absolutely anything.\n+\n+Therefore it is prohibited to define custom symbolic methods, while their use with the 3rd-party libraries should be as limited as possible. Naturally, using unicode characters, which is also allowed by the language, strictly prohibited as well.\n+\n+Additionally, using the infix notation for calling regular, non-symbolic methods is discouraged and could be used only if it significantly increases readability. One example of a sufficiently motivated use of infix notation are matchers and other parts of the tests definition in ScalaTest.\n+\n+Scala also allows calling methods using the postfix notation, when there is no dot present in the method call:\n+\n+```scala\n+import scala.concurrent.duration._\n+\n+val d = 10 minutes\n+```\n+\n+Postfix method calls are forbidden in any form because they may lead to syntactic ambiguities. Dots should always be used instead:\n+\n+```scala\n+val d = 10.minutes\n+```\n+\n+## Apply method on classes\n+\n+`apply()` method allows to use an object with the function call syntax. With the exception of functions, this may lead to very obscure code; additionally, it may be hard to go to the definition of such method in an IDE.\n+\n+For these reasons defining `apply()` method on classes is forbidden, unless these classes extend one of the standard functional traits. Defining an `apply()` method on `object`s is fine, however: this is a pretty well-known idiom for creating constructor functions:\n+\n+```scala\n+class SomeContainer private () { ... }\n+\n+// This is okay\n+object SomeContainer {\n+  def apply(name: String): SomeContainer = {\n+    val result = new SomeContainer()\n+    ...\n+    result\n+  }\n+}\n+\n+// This is not\n+class CustomFunction {\n+  def apply(x: Int): String = \"'$x'\"\n+}\n+\n+val f = new CustomFunction\n+f(10)\n+```\n+\n+## Call by name\n+\n+Call by name is a way to \"defer\" the computation of a value passed into a function as an argument. It is a counterpart to the regular \"call by value\", when the argument to a function is computed entirely before the function is called:\n+\n+```scala\n+def square(x: Int) = x * x\n+\n+def squareByName(x: => Int) = x * x\n+\n+def x: Int = { println(\"Computing x\"); 8 }\n+\n+square(x)        // prints \"Computing x\" once\n+squareByName(x)  // prints \"Computing x\" twice\n+```\n+\n+Call by name allows the called function to determine when to compute its argument. This allows building incredibly powerful custom control structures, but it may also be a great source of confusion for the developer reading the code which uses such control structures.\n+\n+Therefore, using call by name arguments is forbidden, unless its usage significantly increases readability. In general, if you need to get the semantics of a deferred computation, use a no-arguments function explicitly:\n+\n+```scala\n+def squareDeferred(x: () => Int) = x() * x()\n+\n+squareDeferred(() => x)\n+```\n+\n+This syntax makes the fact that the value is computes multiple times clearly visible, both in the call site and in the called function.\n+\n+## Return statements\n+\n+Scala allows using return statements in order to return from methods early. However, Scala is primarily an expression-based language, therefore using imperative constructs like returns usually hurts readability.\n+\n+Moreover, `return` statements are always bound to the enclosing `def`, therefore, if `return` is used e.g. inside a closure, it results in a `try/catch` for a `NonLocalReturnControl` exception generated by the compiler.\n+\n+The general rule is to avoid using `return`s, however, there are cases when they do increase the clarity of the code. Therefore, whether they are appropriate or not should be decided on a case-by-case basis during code review. Basically, `return` is allowed for the following cases:\n+\n+```scala\n+// As a guard to simplify the control flow:\n+def doSomething(input: String): String = {\n+  if (!valid(input)) {\n+    return \"something went wrong\"\n+  }\n+  ...\n+}\n+\n+// As an early return from loops\n+while (condition) {\n+  if (somethingHappened) {\n+    return\n+  }\n+}\n+```\n+\n+## Macros\n+\n+Scala language supports defining macros, which basically are compile-time transformations of source code. Macros usually have access to the entire information about your code which is available to the compiler, including types, which allow implementing very powerful patterns, like generating boilerplate code for structured types like case classes automatically.\n+\n+However, the current version of macros is notoriously hard to write. The code of macro definitions is usually very obscure. Also macros are often used to create custom DSLs, which not only require reading the source code of the macro to be understood completely, but also often upset the IDE syntax highlighters.\n+\n+For this reason writing custom macros is forbidden in general. Using macros from other libraries, like serialization, is not disallowed, unless they hinder the readability.\n+\n+## Exception handling\n+\n+See the section about error handling for more information about error handling in general. This section is dedicated to the exception handling specifically.\n+\n+Always use braces with the `try-catch-finally` construct, even if the body of the `try` contains one expression:\n+\n+```scala\n+// bad\n+try doSomething()\n+catch {\n+  ...\n+}\n+\n+// good\n+try {\n+  doSomething()\n+} catch {\n+  ...\n+}\n+```\n+\n+Do not catch `Throwable` or ignore exceptions inside `catch` clauses; never *ever* ignore the caught exceptions; at the very least you should log them:\n+\n+```scala\n+try {\n+  ...\n+} catch {\n+  // this is wrong\n+  case e: Throwable => ...\n+}\n+\n+try {\n+  ...\n+} catch {\n+  // this is VERY wrong\n+  case _ =>\n+}\n+```\n+\n+Use `scala.util.control.NonFatal` in case you need to catch \"all\" exceptions:\n+\n+```scala\n+try {\n+  ...\n+} catch {\n+  case NonFatal(e) => logger.error(\"Something bad happened\", e)\n+}\n+```\n+\n+Never write any non-local control flow instructions in the `finally` blocks. This includes `return`s, `throw`s and calling functions which may throw exceptions:\n+\n+```scala\n+try {\n+  ...\n+} finally {\n+  // VERY bad\n+  throw AnotherException()\n+}\n+```\n+\n+## Operation chains\n+\n+Many of the standard and non-standard Scala types contain so-called monadic operators, most notable of them being `map`, `flatMap` and `filter`. Scala collections provide many more operations which can also be chained in the same way.\n+\n+This is a very powerful tool which allows expressing complex patterns very concisely. However, precisely for this reason - because such chains allow the code to be very dense in terms of meaning per line of code - chaining should be used sparingly.\n+\n+In general, follow these rules:\n+\n+1. Avoid chaining more than a few operations. The actual number will vary depending on the situation, but it usually should not be more than 5-7 operations at max. Split longer chains by creating temporary variables.\n+\n+2. As a follow-up to the previous rule, the maximum number of chained operations heavily depends on the size of the code which is passed to the combinator functions. In other words, you should chain less operations if the lambdas you used are relatively large. The opposite does not hold, however: you shouldn't chain more operations just because your lambdas are small; while this may make sense depending on the situation, splitting chains and saving parts of expressions in separate variables is almost always a good thing.\n+\n+3. As a rule of thumb, if understanding what a particular sequence of operations does takes more than 5-10 seconds, you should try to rewrite it in a simpler way.\n+\n+Here is an example copied from the Twitter's Effective Scala:\n+\n+```scala\n+val votes = Seq((\"scala\", 1), (\"java\", 4), (\"scala\", 10), (\"scala\", 1), (\"python\", 10))\n+val orderedVotes = votes\n+  .groupBy(_._1)\n+  .map { case (which, counts) => \n+    (which, counts.foldLeft(0)(_ + _._2))\n+  }.toSeq\n+  .sortBy(_._2)\n+  .reverse\n+```\n+\n+This piece of code is incomprehensible to anyone except its original author, and even they will forget what they meant in a very short time. Splitting the chain in logical parts and avoiding tuple accessors in favor of using named parameters allows to make the code much clearer:\n+\n+```scala\n+val votesByLang = votes groupBy { case (lang, _) => lang }\n+val sumByLang = votesByLang map {\n+  case (lang, counts) =>\n+    val countsOnly = counts map { case (_, count) => count }\n+    (lang, countsOnly.sum)\n+}\n+val orderedVotes = sumByLang.toSeq\n+  .sortBy { case (_, count) => count }\n+  .reverse\n+```\n+\n+## Operations nesting and `for` comprehensions\n+\n+`for` comprehensions are a very nice syntactic sugar in Scala which allows expressing certain patterns in a very clean way. Of course, just like any other feature, it is crucial not to overuse it.\n+\n+As a rule of thumb, prefer `for` comprehensions to nested `flatMap`s and `map`s, for example, when you need to flatten several collections. `for` comprehensions are rewritten internally into a nested sequence of method calls, so be careful for using `for`s in performance-critical code.\n+\n+Be aware of implications of using `for` comprehensions for futures. See the section on concurrency for more on that.\n+\n+### Using `for` comprehensions for different types\n+\n+`for` comprehensions may be used with types which have `flatMap`, `map` and `withFilter` methods, and they do not guard you from using different types for each binding clause if it is allowed by typing:\n+\n+```scala\n+val ints = Vector(1, 2, 4, 5)\n+val m = Map(1 -> \"a\", 3 -> \"c\")\n+\n+for {\n+  n <- ints\n+  s <- m.get(n)\n+} yield s\n+```\n+\n+This compiles, even though `ints` is of type `Vector[Int]` and `m.get(n)` is of type `Option[String]`. This is compiled into\n+\n+```scala\n+ints.flatMap(n => m.get(n))\n+```\n+\n+`flatMap` on Scala collections allows its argument function to return anything convertible to an iterable, and `Option[T]` satisfies this requirement. This makes the code harder to understand and, in some subtle cases, may lead to unexpected behavior, in particular, when collections with uniqueness semantics of keys or values (like maps or sets) are used. Therefore, in most cases when you need to iterate over multiple collections in a nested fashion, convert them to a common type. Usually it makes sense to use `.iterator` for that:\n+\n+```scala\n+val resultsIterator = for {\n+  (interface, peers) <- signals.iterator\n+  (peer, values) <- peers.iterator\n+  value <- values.iterator\n+} yield interface -> value\n+\n+val results = resultsIterator.toMap\n+```\n+\n+## String interpolation\n+\n+Scala allows writing references to other variables in scope inside strings using a special syntax:\n+\n+```scala\n+val n = 10\n+println(s\"The value is $n, for your information\")\n+```\n+\n+This syntax should be used instead of string formatting:\n+\n+```scala\n+// bad\n+println(\"The value is %s, for your information\".format(n))\n+```\n+\n+and instead of explicit concatenation:\n+\n+```scala\n+// also bad\n+println(\"The value is \" + n + \", for your information\")\n+```\n+\n+Avoid using long expressions inside the string, though; if computation is long, store it in a lazy variable or a `def`:\n+\n+```scala\n+val results: Map[String, Either[Vector[Error], Unit]] = ...\n+\n+// bad\n+logger.error(s\"Errors happened: ${errors.valuesIterator.flatMap(_.left.toOption).flatten.mkString(\", \")}\")\n+\n+// good\n+def errorsIterator = for {\n+  result <- results.valuesIterator\n+  errors <- result.left.toOption.iterator\n+  error <- errors.iterator\n+} yield error\n+\n+def errorsString = errorsIterator.mkString(\", \")\n+\n+logger.error(s\"Errors happened: $errorsString\")\n+```\n+\n+The good variant is longer, but its intention is clearer for an unaccustomed reader.\n+\n+## Tuples\n+\n+Tuples are ubiquitous in Scala; they are used very often to carry around values of several different types together. Maps in Scala use tuples to represent their entries. However, tuples have a big drawback: they do not assign semantic meaning to the structure they represent.\n+\n+It is acceptable for use cases when they are used extremely frequently, and the lack of such meaning is not harmful: map entries is a prominent example of this. However, avoid storing them in data structures as fields or as values of a collection, because it only makes things obscure. Compare:\n+\n+```scala\n+val actions: Map[(String, String), (Cancellable, Deadline, String)] = ...\n+\n+// vs\n+\n+case class PropertyId(interface: String, key: String)\n+case class ScheduledAction(timer: Cancellable,\n+                           finalDeadline: Deadline,\n+                           payload: String)\n+val actions: Map[PropertyId, ScheduledAction] = ...\n+```\n+\n+Case classes essentially are named tuples, and it is very easy to define them in Scala, so don't hesitate to do it.\n+\n+This gets even more prominent when there is a need to access individual fields, for example, when iterating. Do not ever write this:\n+\n+```scala\n+val joinedPayloadByInterface = actions.iterator\n+  .map(kv => kv._1._1 -> kv._2._3).toVector\n+  .groupBy(_._1)\n+  .map(kv => kv._1 -> kv._2.mkString)\n+```\n+\n+This is much better:\n+\n+```scala\n+val joinedPayloadByInterface = actions.iterator\n+  .map { case (propId, action) => propId.interface -> action.payload }\n+  .toVector\n+  .groupBy { case (interface, _) => interface }\n+  .map { case (interface, payloads) => interface -> payloads.mkString }\n+```\n+\n+And even this is rather complex; split the chained operations into several variable bindings:\n+\n+```scala\n+val singlePayloadByInterface = actions.iterator\n+  .map { case (propId, action) => propId.interface -> action.payload }\n+  .toVector\n+\n+val allPayloadsByInterface = singlePayloadByInterface\n+  .groupBy { case (interface, _) => interface }\n+\n+val joinedPayloadByInterface = allPayloadsByInterface\n+  .map { case (interface, payloads) => interface -> payloads.mkString }\n+```\n+\n+This way the intention of the code is very clear even to a relatively casual reader.\n+\n+# Concurrency (TODO)\n+\n+# Patterns and architecture\n+\n+Scala is a multi-paradigm language, combining elements from functional and object-oriented programming. However, this is dangerous combination which may result in a very obscure code, if from both paradigms are used indiscriminately.\n+\n+As a general rule, object-oriented patterns should be used to model the high-level architecture of the program, while functional patterns should be used locally, to write the actual implementation code. Think of object-oriented design as a strategy, and of functional patterns as tactics: apply the commonly known object-oriented patterns when it is necessary to structure the overall program structure, and use functional idioms when you're writing concrete code which manipulates concrete data.\n+\n+Of course, it is sometimes difficult to make a clean separation, for example, relying on immutability leads to creation of many ADTs, which definitely affect the high-level structure of the program, and vice versa, using dependency injection patterns have very noticeable effect on the concrete implementation. But this approach allows ruling out harmful practices like using high-level functional idioms to structure the overall program (e.g. trying to design the entire program workflow as a monad transformer stack) or blindly using object-oriented patterns to structure low level code (e.g. using virtual dispatch with a trait hierarchy where a simple match would do nicely).\n+\n+\n+## Cake pattern\n+\n+See the full rule description [here][cake-pattern].\n+\n+In short, while the cake pattern is nice in theory, it is hard to get it right and take all the necessary things like dependencies lifetime into account. It also makes testing more difficult as the number of dependencies of different cake components grow.\n+\n+Therefore, the cake pattern must not be used to structure dependencies of different components. Other, more conventional tools like dependency injection libraries or even manual dependency passing should be used instead.\n+\n+  [cake-pattern]: https://github.com/alexandru/scala-best-practices/blob/master/sections/3-architecture.md#31-should-not-use-the-cake-pattern\n+  \n+## Type classes\n+\n+Type classes are a pattern which relies on implicits resolution to inject pieces of functionality based on one or more types. A classic example of a type class is `Ordering`:\n+\n+```scala\n+trait Ordering[-T] {\n+  def compare(left: T, right: T): Int\n+}\n+\n+object Ordering {\n+  implicit object IntOrdering extends Ordering[Int] {\n+    override def compare(left: Int, right: Int): Int = left - right\n+  }\n+}\n+\n+def sorted(v: Vector[T])(implicit ord: Ordering[T]): Vector[T] = {\n+  ...\n+}\n+\n+// IntOrdering is injected automatically as\n+// the implicit parameter for `sorted`\n+val s = sorted(Vector(4, 2, 7, 1, 3))\n+```\n+\n+Type classes are very similar to regular interfaces/traits but allow adding \"implementations\" to types without changing their `extends` clause. \n+\n+So, type classes are a very powerful tool, but, as usual, if they are overused, they can lead to very confusing code. The need to declare custom type classes should be exceedingly rare, therefore unless they significantly increase the clarity of the architecture, they should not be used - regular object-oriented features like traits should be used instead.\n+\n+However, many important libraries, in particular, for serialization, provide their type classes which are expected to be implemented for custom types. This is usually unavoidable and in some cases lead to reduction of boilerplate code. For example, instead of writing custom low-level serializers for a class to JSON representation, using a predefined method to generate the corresponding type class instance will lead to more succinct and understandable code.\n+\n+Therefore, you may write such implementations. See the section on implicit values for more information on how to handle them.\n+\n+\n+## Error handling\n+\n+Exceptions are ubiquitous in the JVM ecosystem, however, by their nature they may make control flow less understandable and clear because they are essentially nonlocal returns - they bubble up the call stack without explicit return statements.\n+\n+Therefore, basing the control flow on exceptions is discouraged. Not only it makes the code less obvious, it also has performance implications - stack unwinding is not free. Do not use exceptions as a substitute for regular control flow instructions.\n+\n+### Encoding errors in types\n+\n+Exceptions should be used, as their name states, in exceptional situations, i.e. when something went wrong and the program cannot continue further because of a broken invariant. This means that you should not use exceptions when it is possible for an error to occur and you want the user of your code to handle it. In such cases errors should be encoded explicitly, using `Option`, `Try`, `Future` or `Either`-like types.\n+\n+All rules described in the section on using chained method calls apply to the `Try` values, of course.\n+\n+## Functional programming","path":"Readme.md","position":1079,"original_position":1079,"commit_id":"1501237fc4642c2f0215cd4272f6d52be2534c5f","original_commit_id":"1501237fc4642c2f0215cd4272f6d52be2534c5f","user":{"login":"netvl","id":280456,"avatar_url":"https://avatars.githubusercontent.com/u/280456?v=3","gravatar_id":"","url":"https://api.github.com/users/netvl","html_url":"https://github.com/netvl","followers_url":"https://api.github.com/users/netvl/followers","following_url":"https://api.github.com/users/netvl/following{/other_user}","gists_url":"https://api.github.com/users/netvl/gists{/gist_id}","starred_url":"https://api.github.com/users/netvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netvl/subscriptions","organizations_url":"https://api.github.com/users/netvl/orgs","repos_url":"https://api.github.com/users/netvl/repos","events_url":"https://api.github.com/users/netvl/events{/privacy}","received_events_url":"https://api.github.com/users/netvl/received_events","type":"User","site_admin":false},"body":"Okay, I'll try to give more precise definitions.","created_at":"2016-07-15T14:12:05Z","updated_at":"2016-07-15T14:12:05Z","html_url":"https://github.com/netvl/scala-guidelines/pull/1#discussion_r70979117","pull_request_url":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/netvl/scala-guidelines/pulls/comments/70979117"},"html":{"href":"https://github.com/netvl/scala-guidelines/pull/1#discussion_r70979117"},"pull_request":{"href":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1","id":77413247,"html_url":"https://github.com/netvl/scala-guidelines/pull/1","diff_url":"https://github.com/netvl/scala-guidelines/pull/1.diff","patch_url":"https://github.com/netvl/scala-guidelines/pull/1.patch","issue_url":"https://api.github.com/repos/netvl/scala-guidelines/issues/1","number":1,"state":"open","locked":false,"title":"Initial draft of the document","user":{"login":"netvl","id":280456,"avatar_url":"https://avatars.githubusercontent.com/u/280456?v=3","gravatar_id":"","url":"https://api.github.com/users/netvl","html_url":"https://github.com/netvl","followers_url":"https://api.github.com/users/netvl/followers","following_url":"https://api.github.com/users/netvl/following{/other_user}","gists_url":"https://api.github.com/users/netvl/gists{/gist_id}","starred_url":"https://api.github.com/users/netvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netvl/subscriptions","organizations_url":"https://api.github.com/users/netvl/orgs","repos_url":"https://api.github.com/users/netvl/repos","events_url":"https://api.github.com/users/netvl/events{/privacy}","received_events_url":"https://api.github.com/users/netvl/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-07-14T07:48:33Z","updated_at":"2016-07-15T14:12:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5ac03f39ebb689962082e842dd7e2ff10a01db06","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1/commits","review_comments_url":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1/comments","review_comment_url":"https://api.github.com/repos/netvl/scala-guidelines/pulls/comments{/number}","comments_url":"https://api.github.com/repos/netvl/scala-guidelines/issues/1/comments","statuses_url":"https://api.github.com/repos/netvl/scala-guidelines/statuses/1501237fc4642c2f0215cd4272f6d52be2534c5f","head":{"label":"netvl:initial-version","ref":"initial-version","sha":"1501237fc4642c2f0215cd4272f6d52be2534c5f","user":{"login":"netvl","id":280456,"avatar_url":"https://avatars.githubusercontent.com/u/280456?v=3","gravatar_id":"","url":"https://api.github.com/users/netvl","html_url":"https://github.com/netvl","followers_url":"https://api.github.com/users/netvl/followers","following_url":"https://api.github.com/users/netvl/following{/other_user}","gists_url":"https://api.github.com/users/netvl/gists{/gist_id}","starred_url":"https://api.github.com/users/netvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netvl/subscriptions","organizations_url":"https://api.github.com/users/netvl/orgs","repos_url":"https://api.github.com/users/netvl/repos","events_url":"https://api.github.com/users/netvl/events{/privacy}","received_events_url":"https://api.github.com/users/netvl/received_events","type":"User","site_admin":false},"repo":{"id":63314136,"name":"scala-guidelines","full_name":"netvl/scala-guidelines","owner":{"login":"netvl","id":280456,"avatar_url":"https://avatars.githubusercontent.com/u/280456?v=3","gravatar_id":"","url":"https://api.github.com/users/netvl","html_url":"https://github.com/netvl","followers_url":"https://api.github.com/users/netvl/followers","following_url":"https://api.github.com/users/netvl/following{/other_user}","gists_url":"https://api.github.com/users/netvl/gists{/gist_id}","starred_url":"https://api.github.com/users/netvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netvl/subscriptions","organizations_url":"https://api.github.com/users/netvl/orgs","repos_url":"https://api.github.com/users/netvl/repos","events_url":"https://api.github.com/users/netvl/events{/privacy}","received_events_url":"https://api.github.com/users/netvl/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/netvl/scala-guidelines","description":null,"fork":false,"url":"https://api.github.com/repos/netvl/scala-guidelines","forks_url":"https://api.github.com/repos/netvl/scala-guidelines/forks","keys_url":"https://api.github.com/repos/netvl/scala-guidelines/keys{/key_id}","collaborators_url":"https://api.github.com/repos/netvl/scala-guidelines/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/netvl/scala-guidelines/teams","hooks_url":"https://api.github.com/repos/netvl/scala-guidelines/hooks","issue_events_url":"https://api.github.com/repos/netvl/scala-guidelines/issues/events{/number}","events_url":"https://api.github.com/repos/netvl/scala-guidelines/events","assignees_url":"https://api.github.com/repos/netvl/scala-guidelines/assignees{/user}","branches_url":"https://api.github.com/repos/netvl/scala-guidelines/branches{/branch}","tags_url":"https://api.github.com/repos/netvl/scala-guidelines/tags","blobs_url":"https://api.github.com/repos/netvl/scala-guidelines/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/netvl/scala-guidelines/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/netvl/scala-guidelines/git/refs{/sha}","trees_url":"https://api.github.com/repos/netvl/scala-guidelines/git/trees{/sha}","statuses_url":"https://api.github.com/repos/netvl/scala-guidelines/statuses/{sha}","languages_url":"https://api.github.com/repos/netvl/scala-guidelines/languages","stargazers_url":"https://api.github.com/repos/netvl/scala-guidelines/stargazers","contributors_url":"https://api.github.com/repos/netvl/scala-guidelines/contributors","subscribers_url":"https://api.github.com/repos/netvl/scala-guidelines/subscribers","subscription_url":"https://api.github.com/repos/netvl/scala-guidelines/subscription","commits_url":"https://api.github.com/repos/netvl/scala-guidelines/commits{/sha}","git_commits_url":"https://api.github.com/repos/netvl/scala-guidelines/git/commits{/sha}","comments_url":"https://api.github.com/repos/netvl/scala-guidelines/comments{/number}","issue_comment_url":"https://api.github.com/repos/netvl/scala-guidelines/issues/comments{/number}","contents_url":"https://api.github.com/repos/netvl/scala-guidelines/contents/{+path}","compare_url":"https://api.github.com/repos/netvl/scala-guidelines/compare/{base}...{head}","merges_url":"https://api.github.com/repos/netvl/scala-guidelines/merges","archive_url":"https://api.github.com/repos/netvl/scala-guidelines/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/netvl/scala-guidelines/downloads","issues_url":"https://api.github.com/repos/netvl/scala-guidelines/issues{/number}","pulls_url":"https://api.github.com/repos/netvl/scala-guidelines/pulls{/number}","milestones_url":"https://api.github.com/repos/netvl/scala-guidelines/milestones{/number}","notifications_url":"https://api.github.com/repos/netvl/scala-guidelines/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/netvl/scala-guidelines/labels{/name}","releases_url":"https://api.github.com/repos/netvl/scala-guidelines/releases{/id}","deployments_url":"https://api.github.com/repos/netvl/scala-guidelines/deployments","created_at":"2016-07-14T07:45:34Z","updated_at":"2016-07-14T07:45:34Z","pushed_at":"2016-07-14T07:48:33Z","git_url":"git://github.com/netvl/scala-guidelines.git","ssh_url":"git@github.com:netvl/scala-guidelines.git","clone_url":"https://github.com/netvl/scala-guidelines.git","svn_url":"https://github.com/netvl/scala-guidelines","homepage":null,"size":23,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"netvl:master","ref":"master","sha":"e9b5a58ae3b47051dd5be07dbd8fc4be53f26a1b","user":{"login":"netvl","id":280456,"avatar_url":"https://avatars.githubusercontent.com/u/280456?v=3","gravatar_id":"","url":"https://api.github.com/users/netvl","html_url":"https://github.com/netvl","followers_url":"https://api.github.com/users/netvl/followers","following_url":"https://api.github.com/users/netvl/following{/other_user}","gists_url":"https://api.github.com/users/netvl/gists{/gist_id}","starred_url":"https://api.github.com/users/netvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netvl/subscriptions","organizations_url":"https://api.github.com/users/netvl/orgs","repos_url":"https://api.github.com/users/netvl/repos","events_url":"https://api.github.com/users/netvl/events{/privacy}","received_events_url":"https://api.github.com/users/netvl/received_events","type":"User","site_admin":false},"repo":{"id":63314136,"name":"scala-guidelines","full_name":"netvl/scala-guidelines","owner":{"login":"netvl","id":280456,"avatar_url":"https://avatars.githubusercontent.com/u/280456?v=3","gravatar_id":"","url":"https://api.github.com/users/netvl","html_url":"https://github.com/netvl","followers_url":"https://api.github.com/users/netvl/followers","following_url":"https://api.github.com/users/netvl/following{/other_user}","gists_url":"https://api.github.com/users/netvl/gists{/gist_id}","starred_url":"https://api.github.com/users/netvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netvl/subscriptions","organizations_url":"https://api.github.com/users/netvl/orgs","repos_url":"https://api.github.com/users/netvl/repos","events_url":"https://api.github.com/users/netvl/events{/privacy}","received_events_url":"https://api.github.com/users/netvl/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/netvl/scala-guidelines","description":null,"fork":false,"url":"https://api.github.com/repos/netvl/scala-guidelines","forks_url":"https://api.github.com/repos/netvl/scala-guidelines/forks","keys_url":"https://api.github.com/repos/netvl/scala-guidelines/keys{/key_id}","collaborators_url":"https://api.github.com/repos/netvl/scala-guidelines/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/netvl/scala-guidelines/teams","hooks_url":"https://api.github.com/repos/netvl/scala-guidelines/hooks","issue_events_url":"https://api.github.com/repos/netvl/scala-guidelines/issues/events{/number}","events_url":"https://api.github.com/repos/netvl/scala-guidelines/events","assignees_url":"https://api.github.com/repos/netvl/scala-guidelines/assignees{/user}","branches_url":"https://api.github.com/repos/netvl/scala-guidelines/branches{/branch}","tags_url":"https://api.github.com/repos/netvl/scala-guidelines/tags","blobs_url":"https://api.github.com/repos/netvl/scala-guidelines/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/netvl/scala-guidelines/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/netvl/scala-guidelines/git/refs{/sha}","trees_url":"https://api.github.com/repos/netvl/scala-guidelines/git/trees{/sha}","statuses_url":"https://api.github.com/repos/netvl/scala-guidelines/statuses/{sha}","languages_url":"https://api.github.com/repos/netvl/scala-guidelines/languages","stargazers_url":"https://api.github.com/repos/netvl/scala-guidelines/stargazers","contributors_url":"https://api.github.com/repos/netvl/scala-guidelines/contributors","subscribers_url":"https://api.github.com/repos/netvl/scala-guidelines/subscribers","subscription_url":"https://api.github.com/repos/netvl/scala-guidelines/subscription","commits_url":"https://api.github.com/repos/netvl/scala-guidelines/commits{/sha}","git_commits_url":"https://api.github.com/repos/netvl/scala-guidelines/git/commits{/sha}","comments_url":"https://api.github.com/repos/netvl/scala-guidelines/comments{/number}","issue_comment_url":"https://api.github.com/repos/netvl/scala-guidelines/issues/comments{/number}","contents_url":"https://api.github.com/repos/netvl/scala-guidelines/contents/{+path}","compare_url":"https://api.github.com/repos/netvl/scala-guidelines/compare/{base}...{head}","merges_url":"https://api.github.com/repos/netvl/scala-guidelines/merges","archive_url":"https://api.github.com/repos/netvl/scala-guidelines/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/netvl/scala-guidelines/downloads","issues_url":"https://api.github.com/repos/netvl/scala-guidelines/issues{/number}","pulls_url":"https://api.github.com/repos/netvl/scala-guidelines/pulls{/number}","milestones_url":"https://api.github.com/repos/netvl/scala-guidelines/milestones{/number}","notifications_url":"https://api.github.com/repos/netvl/scala-guidelines/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/netvl/scala-guidelines/labels{/name}","releases_url":"https://api.github.com/repos/netvl/scala-guidelines/releases{/id}","deployments_url":"https://api.github.com/repos/netvl/scala-guidelines/deployments","created_at":"2016-07-14T07:45:34Z","updated_at":"2016-07-14T07:45:34Z","pushed_at":"2016-07-14T07:48:33Z","git_url":"git://github.com/netvl/scala-guidelines.git","ssh_url":"git@github.com:netvl/scala-guidelines.git","clone_url":"https://github.com/netvl/scala-guidelines.git","svn_url":"https://github.com/netvl/scala-guidelines","homepage":null,"size":23,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1"},"html":{"href":"https://github.com/netvl/scala-guidelines/pull/1"},"issue":{"href":"https://api.github.com/repos/netvl/scala-guidelines/issues/1"},"comments":{"href":"https://api.github.com/repos/netvl/scala-guidelines/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/netvl/scala-guidelines/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/netvl/scala-guidelines/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/netvl/scala-guidelines/statuses/1501237fc4642c2f0215cd4272f6d52be2534c5f"}}}}
{"actor":{"display_login":"netvl"}}