Upload
-
View
55
Download
4
Embed Size (px)
Citation preview
Как изучить Scala и не открыть портал в
ад?
Сергей Петунин
Путь в Scala
• Кривая обучаемости
• Документация
• Лучшие практики
Кривая обучаемости
Кривая обучаемости: уровни
Прикладной разработчик
Разработчик библиотек
Общий уровень Scala
Beginning A1 Beginning
Intermediate A2 Junior L1 Intermediate
Expert A3 Senior L2 Advanced
Expert L3 Expert
Кривая обучаемости: уровни
Прикладной разработчик
Разработчик библиотек
Общий уровень Scala
Beginning A1 (for-expressions)
Beginning
Intermediate A2 Junior L1 Intermediate
Expert A3 Senior L2(advanced for-expressions, self-types)
Advanced
Expert L3 (implicits)
Expert
Implicits: проблематика
Модификация поведения кода, который мы не можем или не хотим изменять:
• Чужие библиотеки (pimp-my-library)
• Неинтрузивные изменения
• Сквозная функциональность
Динамические языки: Monkey-patching
class String def upcase self.reverse endend
"hello".upcase=> "olleh"
Отсутствие прослеживаемости!
Языки со статической типизацией: Расширения, категории
extension String {
func reverse() -> String {
let revChars = characters.reverse() return String(revChars)
}
}
Java
• Аспекты
• Модификация байт-кода
• Рефлексия
Java: monkey-patching?
@Before("execution(* *..*Service.*())")public void doBeforeAnyServiceMethod() { System.out.println("Unexpected stuff!");}
Scala: implicit defs
implicit def strToInt(s: String): Int = { java.lang.Integer.parseInt(s)}
println(Math.max("5", "6"))
Implicit defs: правила
• Marking rule
• Только определения с ключевым словом implicit
• Scope rule
• Импорты одиночного идентификатора
• Объект-компаньон исходного или целевого класса
• One-at-a-time rule
• Применяется только один implicit
• Explicits first
• Если можно обойтись без implicit, то он не применяется
Implicit defs: прослеживаемость
object MyImplicits {
implicit def strToDouble(s: String): Double = { java.lang.Double.parseDouble(s) // s.toDouble ??? }
}
Implicit defs: прослеживаемость
Implicit defs: прослеживаемость
Документация
Документация: Spring
Документация: Spring
Документация: Play
Документация: Play
Построитель запросов в Slick
val monadicInnerJoin = for { c <- coffees s <- suppliers if s.supID === s.id} yield (c.name, s.name)
// Компилируется в SQL:// select x2."COF_NAME", x3."SUP_NAME"// from "COFFEES" x2, "SUPPLIERS" x3// where x2.”SUP_ID” = x3.”SUP_ID”
Монады
• Операция return (в Scala — конструктор)
• return :: a -> m a
• Операция bind (в Scala — map/flatMap)
• (>>=) :: m a -> (a -> m b) -> m b
• Монадические законы
Монада List и for-включение
// декартово произведение списков // с использованием for-включения: val peoplePositions = for { person <- people position <- positions } yield s"$person, $position"
Монада List без сахара
// декартово произведение списков // прямым вызовом flatMap и map: val peoplePositions2 = people.flatMap { person => positions.map { position => s"$person, $position" } }
Монада Future и for-включение
def getFuture1 = Future { "1337"}def getFuture2(string: String) = Future { string.toInt } val composedFuture = for { result1 <- getFuture1 result2 <- getFuture2(result1) } yield result2
Монада Future без сахара
val composedFuture2 = getFuture1.flatMap { result1 => getFuture2(result1).map { result2 => result2 } }
Построитель запросов в Slick
val monadicInnerJoin = for { c <- coffees s <- suppliers if s.supID === s.id} yield (c.name, s.name)
// Компилируется в SQL:// select x2."COF_NAME", x3."SUP_NAME"// from "COFFEES" x2, "SUPPLIERS" x3// where x2.”SUP_ID” = x3.”SUP_ID”
Действия в Slick: ещё одна монада
// делаем из запроса DBIO-действиеval action1 = monadicInnerJoin.result
// заворачиваем действие в транзакциюval txAction1 = action1.transactionally
Действия в Slick: ещё одна монада
// делаем DBIO-действие из какой-то // произвольной функцииval action2 = DBIO.successful { println("Делаем что-то в транзакции...")}
Действия в Slick: ещё одна монада
// делаем композитное действие // из четырёх действийval compAction = for { result <- action1 _ <- action2 personCount <- action3 phoneCount <- action4} yield personCount + phoneCount
val actionFuture = db.run(compAction.transactionally)
Лучшие практики
Лучшие практики: Dependency Injection
• Cake pattern
• Структурная типизация
• Implicits
• Reader Monad
• DI-фреймворки
Self type
trait Persistable { def persist()}
trait DomainObject { this: Persistable => // USES-A
def businessLogic() = { // ... persist() }}
Лучшие практики: Dependency Injection
Итоги
• Кривая обучения
• Да, она крутая — учиться придётся много.
• Документация
• Её недостаточно, изучайте код и концепции.
• Лучшие практики
• Их много, выбирайте с умом.
Спасибо за внимание!Сергей Петунин
[email protected]@forketyforkforketyfork