Перевод статьи технического директора компании CrowdStrike, о том, как и почему они перешли со Scala на Go по мере роста компании с 5 до 200+ человек.
Scala долгое время была частью стека нашей компании CrowdStrike, по сути даже главным языком. Я помогал внедрять Scala когда мы начали разрабатывать наш софт в 2012-м году. На самом деле, это было даже одной из главных причин моего перехода в CrowdStrike. Несколько основных разработчиков были заинтересованы во внедрении Scala, так что это был хороший вариант для всех.
Я перешёл из компании Gravity, которая достаточно активно использовала Scala. Это был основной язык в компании. Я привык к нему, мне он нравился, я видел его мощь и был уверен, что смогу предотвратить некоторые из сложностей, которые я видел в Scala, по мере того, как CrowdStrike будет расти. Мы делали высоконагруженную аналитику, batch-задачи на Hadoop и наш Chief Architect (привет, Биссел!) использовал лямбда-архитектуру задолго до того, как это стало модно.
Недавняя цитата от одного из наших senior-разработчиков заставила меня таки написать этот пост, описывающий, почему мы перевели большую часть нашего стека на Go, и почему новые сервисы мы по-умолчанию теперь пишем именно на Go.
Вместо того, чтобы заставлять ждать читателя до конца поста, я сразу скажу, что Scala не покидает наш стек полностью. По сути, она остается дополнением к Go в тех местах, где он не блещет. Scala является важным звеном в нашем стеке машинного обучения и аналитики. Она работает в связке с Java-продуктами, которые мы используем, и её возможность предоставлять приятный DSL для наших аналитиков, делает Scala до сих пор хорошим выбором. Но она стала больше специализированным инструментом вместо языка по-умолчанию.
Я передам вам эту историю через призму взгляда Технического Директора. Призму, в которой вам нужно расширять компанию с её ранних дней и 5 разработчиков до 200+ программистов по мере роста бизнеса. Это всё о том, чтобы иметь поддерживаемую кодовую базу, в которой люди легко могут переходить из проекта в проект и нанимать новых людей легко и быстро.
Я помню как я впервые увидел потенциальные проблемы в масштабируемости Scala в Gravity ещё в 2009/2010-м. Был конец рабочего дня, когда мы получили информацию о серьёзной проблеме в продакшене у одного из наших крупных клиентов. Несколько человек начали исследовать проблему, и мы смогли локализировать код, в котором случился сбой. Но настоящая проблема оказалась в том, что мы понятия не имели, что этот код делал. Мы упёрлись в странный символ, который мы никогда ранее в наших проектах не встречали. Это spaceship operator <|*|>. Кто-то сказал вслух «что это за хр**нь?». Там происходила какая-то неявная магия, которая была совсем неочевидна. Cmd-B чтобы перейти к методу не помогло, так как наша IDE не могла найти символ (IDE с тех пор улучшились). Быстрое гугление по "<|*|>" тоже не принесло результатов. Мы были загнаны в тупик.
![](https://habrastorage.org/r/w1560/files/9ca/2b7/4ea/9ca2b74ead584806a5e54de0a983ff26.png)
Программист, который написал этот код, был недоступен, так как находился в отпуске, поэтому нам нужно было разобраться самостоятельно. Мы обнаружили недавно добавленную новую библиотеку, которая называлась scalaz, и через несколько часов мы нашли этот мистический символ и разобрались, что он делал, выкатили фикс, и все были счастливы. Но этот момент превратил фикс, который должен был занять пару минут, в многочасовую погоню. Это был момент, после которого я стал видеть раскол в нашей команде разработчиков.
Scala — это очень мощный язык, рождённый в академической среде, и который даёт вам достаточно гибкости, чтобы легко начать писать «write-once» код. Обычно Scala-разработчики разделяются на два лагеря — «Это лучший вариант Java»-лагерь и «Я (сердце) Аппликативные Функторы»-лагерь.
![](https://habrastorage.org/r/w1560/files/764/b6a/898/764b6a8984b7453db94f14ac14623c10.png)
В лагере «Это лучший вариант Java» любят лаконичность Scala и стандартные фичи, которые делают Scala в целом более приятной, чем Java. В их коде есть функциональное программирование, но без фанатизма. В лагере же «Я (сердце) Аппликативные Функторы» функциональный мир расцветает на всю, и народ начинает углублять свои познания, принося свой уже функциональный бекграунд из языков вроде Haskell.
На моём опыте, я разделял эти два лагеря, и в каждом были отличные программисты, так что я не мог сказать, что один лагерь хуже или лучше другого. В полу-функциональном лагере было разве что потенциально больше более универсальных разработчиков, работающих с разными языками, или тех, кто не хотел изучать лямбда-исчисление, чтобы работать над API-сервером.
Как пример, вот кусочек кода одного из проекта, написанного одним из наших опытных Scala разработчиков:
Кто-то из вас посмотрит и скажет, что это блестяще, но кто-то скажет — WTF? Там были тысячи подобных строк кода. Это были те случаи, когда вся команда могла работать с кодом, но половина не хотела иметь с этим кодом дела вообще. Разработчик, который писал это — выдающийся программист, но тот факт, что его код раскалывал всю команду, было проблемой.
По мере роста команды этот раскол становился более очевидным, когда нужно было нанимать новых людей. У Scala есть немало мелких, но неприятных моментов вроде настройки среды разработки, боль с SBT, проблемы с настройкой IDE, медленное время сборки, большие старые JARы… И в добавок к этому большая доза новых концептов ScalaZ, что всё вместе приводило к долгому времени входа в проекты и замедлению продуктивности разработчиков. Теперь нам нужно было отвлекать разработчиков на предварительное обучение новичков, что также замедляло процессы. SBT тоже было отдельной болячкой. Всегда так получалось, что есть только один человек, который действительно понимает, что, блин, делает SBT и может разрулить проблемы у остальных.
И это не было чем-то уникальным в компаниях, на которые я работал. Twitter проходил через эти же проблемы роста, равно как и другие компании, с которыми я имел возможность общаться на конференциях, и другие люди, работающие со Scala, которых я знал. Это известная тема, на самом деле. В то время, когда вы можете быть невероятно продуктивны со Scala в маленьких командах, рост команды больше 50 человек превращается в тяжелую борьбу.
И в этот момент на сцену выходит Go. Одной из причин появления Go была возможность дать программистам быть более продуктивными, уменьшить количество способов, которыми можно сделать одно и то же и иметь очень определённый взгляд на мир с точки зрения компилятора. Я сопротивлялся Go внутренне некоторое время. Я не хотел ещё более раскалывать команду, заставлять людей учить ещё один язык, поскольку у нас и так было уже несколько технологий в стеке. У нас было внутреннее правило даже не рассматривать технологию, пока не будет хотя бы 3 человека, которые будут готовы поддерживать проблему с этой технологией в продакшене в 3 часа утра. После того, как меня достаточно в него потыкали (спасибо, Sean Berry), и необходимое количество в 3 человека было набрано, я углубился в изучение Go и увидел, что он решает нам массу проблем со Scala на организационном уровне.
Быстрое время компиляции, маленькие бинарники, один файл, встроенное форматирование, отличный инструментарий из коробки, встроенные тесты, профайлеры, отличная модель для конкурентного программирования? Ухты, продано! Мы успешно сделали тестовый проект на Go, потом ещё один, потом ещё, увеличили количество разработчиков, которые взялись за Go, и вскоре Go стал предпочитаемым языком, который люди сами выбирали. Вы можете прыгнуть в любой проект на Go и сразу же понять, что он делает. Скучаю ли я по иммутабельным типам и некоторым великолепным фичам в Scala? Конечно да, но я думаю, поддерживаемость кода слишком важна тут, чтобы упустить Go.
Ещё одним из преимуществ Go было расширение пула разработчиков, которых мы могли нанимать. Мы могли нанять практически любого программиста с разным бекграундом и знать, что он освоит Go за пару недель. Со Scala всегда сначала есть кривая обучения в JVM, мир Java контейнеров, тёмная магия тюнинга JVM и так далее.
Новые разработчики входили теперь в игру за недели, а не за месяцы. Сейчас у нас большинство наших проектов написаны на Go, и последний сопротивляющийся Go программист буквально на днях написал свой первый Go проект и сказал мне следующее: «Ухты, я прочёл код библиотеки один раз и я знал, что она делает. Я прочёл код Scala-версии библиотеки 4 раза и до сих пор не понимаю до конца, как она работает. Теперь я понимаю, почему вы так запали на Go». Это был один из наших senior-разработчиков, который ранее работал в одной из крупнейших web-компаний мира. Весь этот процесс перехода на Go был целиком инициирован снизу нашими разработчиками, и был выбором команды.
Сейчас мы обрабатываем сотни тысяч сообщений в секунду и терабайты данных в день с нашими сервисами на Golang.
В этой статье я не хочу поругать Scala или ScalaZ(я люблю ValidationNel!), но хочу дать больше контекста из реального продакшн мира с более чем 7-летним опытом в двух компаниях. Я по-прежнему использую Scala, и мне нравится играться со Scalding. Некоторые из наших следующих амбициозных проектов будут скорее всего на Scala, но я больше не считаю, что делать его основным языком будет правильным выбором, особенно по мере роста команды. Go с тех пор стал моим языком по-умолчанию.
Go делает процесс разработки слишком простым.
![](https://habrastorage.org/r/w1560/files/42f/3d2/31f/42f3d231f76744b086ddc07c1382b4b0.png)
Scala долгое время была частью стека нашей компании CrowdStrike, по сути даже главным языком. Я помогал внедрять Scala когда мы начали разрабатывать наш софт в 2012-м году. На самом деле, это было даже одной из главных причин моего перехода в CrowdStrike. Несколько основных разработчиков были заинтересованы во внедрении Scala, так что это был хороший вариант для всех.
Я перешёл из компании Gravity, которая достаточно активно использовала Scala. Это был основной язык в компании. Я привык к нему, мне он нравился, я видел его мощь и был уверен, что смогу предотвратить некоторые из сложностей, которые я видел в Scala, по мере того, как CrowdStrike будет расти. Мы делали высоконагруженную аналитику, batch-задачи на Hadoop и наш Chief Architect (привет, Биссел!) использовал лямбда-архитектуру задолго до того, как это стало модно.
Недавняя цитата от одного из наших senior-разработчиков заставила меня таки написать этот пост, описывающий, почему мы перевели большую часть нашего стека на Go, и почему новые сервисы мы по-умолчанию теперь пишем именно на Go.
Вместо того, чтобы заставлять ждать читателя до конца поста, я сразу скажу, что Scala не покидает наш стек полностью. По сути, она остается дополнением к Go в тех местах, где он не блещет. Scala является важным звеном в нашем стеке машинного обучения и аналитики. Она работает в связке с Java-продуктами, которые мы используем, и её возможность предоставлять приятный DSL для наших аналитиков, делает Scala до сих пор хорошим выбором. Но она стала больше специализированным инструментом вместо языка по-умолчанию.
Я передам вам эту историю через призму взгляда Технического Директора. Призму, в которой вам нужно расширять компанию с её ранних дней и 5 разработчиков до 200+ программистов по мере роста бизнеса. Это всё о том, чтобы иметь поддерживаемую кодовую базу, в которой люди легко могут переходить из проекта в проект и нанимать новых людей легко и быстро.
Я помню как я впервые увидел потенциальные проблемы в масштабируемости Scala в Gravity ещё в 2009/2010-м. Был конец рабочего дня, когда мы получили информацию о серьёзной проблеме в продакшене у одного из наших крупных клиентов. Несколько человек начали исследовать проблему, и мы смогли локализировать код, в котором случился сбой. Но настоящая проблема оказалась в том, что мы понятия не имели, что этот код делал. Мы упёрлись в странный символ, который мы никогда ранее в наших проектах не встречали. Это spaceship operator <|*|>. Кто-то сказал вслух «что это за хр**нь?». Там происходила какая-то неявная магия, которая была совсем неочевидна. Cmd-B чтобы перейти к методу не помогло, так как наша IDE не могла найти символ (IDE с тех пор улучшились). Быстрое гугление по "<|*|>" тоже не принесло результатов. Мы были загнаны в тупик.
![](https://habrastorage.org/files/9ca/2b7/4ea/9ca2b74ead584806a5e54de0a983ff26.png)
Программист, который написал этот код, был недоступен, так как находился в отпуске, поэтому нам нужно было разобраться самостоятельно. Мы обнаружили недавно добавленную новую библиотеку, которая называлась scalaz, и через несколько часов мы нашли этот мистический символ и разобрались, что он делал, выкатили фикс, и все были счастливы. Но этот момент превратил фикс, который должен был занять пару минут, в многочасовую погоню. Это был момент, после которого я стал видеть раскол в нашей команде разработчиков.
Scala — это очень мощный язык, рождённый в академической среде, и который даёт вам достаточно гибкости, чтобы легко начать писать «write-once» код. Обычно Scala-разработчики разделяются на два лагеря — «Это лучший вариант Java»-лагерь и «Я (сердце) Аппликативные Функторы»-лагерь.
![](https://habrastorage.org/files/764/b6a/898/764b6a8984b7453db94f14ac14623c10.png)
В лагере «Это лучший вариант Java» любят лаконичность Scala и стандартные фичи, которые делают Scala в целом более приятной, чем Java. В их коде есть функциональное программирование, но без фанатизма. В лагере же «Я (сердце) Аппликативные Функторы» функциональный мир расцветает на всю, и народ начинает углублять свои познания, принося свой уже функциональный бекграунд из языков вроде Haskell.
На моём опыте, я разделял эти два лагеря, и в каждом были отличные программисты, так что я не мог сказать, что один лагерь хуже или лучше другого. В полу-функциональном лагере было разве что потенциально больше более универсальных разработчиков, работающих с разными языками, или тех, кто не хотел изучать лямбда-исчисление, чтобы работать над API-сервером.
Как пример, вот кусочек кода одного из проекта, написанного одним из наших опытных Scala разработчиков:
import scalaz._
import scalaz.std.list._
import scalaz.syntax.monad._
import scalaz.syntax.monoid._
import scalaz.syntax.traverse.{ToFunctorOps => _, _}
class Foo[F[+_] : Monad, A, B](val execute: Foo.Request[A] => F[B], val joins: Foo.Request[A] => B => List[Foo.Request[A]])(implicit J: Foo.Join[A, B]) {
def bar: Foo[({type l[+a]=WriterT[F, Log[A, B], a]})#l, A, B] = {
type TraceW[FF[+_], +AA] = WriterT[FF, Log[A, B], AA]
def execute(request: Request[A]): WriterT[F, Log[A, B], B] =
self.execute(request).liftM[TraceW] :++>> (repr => List(request -> request.response(repr, self.joins(request)(repr))))
----- REDACTED -------
Кто-то из вас посмотрит и скажет, что это блестяще, но кто-то скажет — WTF? Там были тысячи подобных строк кода. Это были те случаи, когда вся команда могла работать с кодом, но половина не хотела иметь с этим кодом дела вообще. Разработчик, который писал это — выдающийся программист, но тот факт, что его код раскалывал всю команду, было проблемой.
По мере роста команды этот раскол становился более очевидным, когда нужно было нанимать новых людей. У Scala есть немало мелких, но неприятных моментов вроде настройки среды разработки, боль с SBT, проблемы с настройкой IDE, медленное время сборки, большие старые JARы… И в добавок к этому большая доза новых концептов ScalaZ, что всё вместе приводило к долгому времени входа в проекты и замедлению продуктивности разработчиков. Теперь нам нужно было отвлекать разработчиков на предварительное обучение новичков, что также замедляло процессы. SBT тоже было отдельной болячкой. Всегда так получалось, что есть только один человек, который действительно понимает, что, блин, делает SBT и может разрулить проблемы у остальных.
И это не было чем-то уникальным в компаниях, на которые я работал. Twitter проходил через эти же проблемы роста, равно как и другие компании, с которыми я имел возможность общаться на конференциях, и другие люди, работающие со Scala, которых я знал. Это известная тема, на самом деле. В то время, когда вы можете быть невероятно продуктивны со Scala в маленьких командах, рост команды больше 50 человек превращается в тяжелую борьбу.
И в этот момент на сцену выходит Go. Одной из причин появления Go была возможность дать программистам быть более продуктивными, уменьшить количество способов, которыми можно сделать одно и то же и иметь очень определённый взгляд на мир с точки зрения компилятора. Я сопротивлялся Go внутренне некоторое время. Я не хотел ещё более раскалывать команду, заставлять людей учить ещё один язык, поскольку у нас и так было уже несколько технологий в стеке. У нас было внутреннее правило даже не рассматривать технологию, пока не будет хотя бы 3 человека, которые будут готовы поддерживать проблему с этой технологией в продакшене в 3 часа утра. После того, как меня достаточно в него потыкали (спасибо, Sean Berry), и необходимое количество в 3 человека было набрано, я углубился в изучение Go и увидел, что он решает нам массу проблем со Scala на организационном уровне.
Быстрое время компиляции, маленькие бинарники, один файл, встроенное форматирование, отличный инструментарий из коробки, встроенные тесты, профайлеры, отличная модель для конкурентного программирования? Ухты, продано! Мы успешно сделали тестовый проект на Go, потом ещё один, потом ещё, увеличили количество разработчиков, которые взялись за Go, и вскоре Go стал предпочитаемым языком, который люди сами выбирали. Вы можете прыгнуть в любой проект на Go и сразу же понять, что он делает. Скучаю ли я по иммутабельным типам и некоторым великолепным фичам в Scala? Конечно да, но я думаю, поддерживаемость кода слишком важна тут, чтобы упустить Go.
Ещё одним из преимуществ Go было расширение пула разработчиков, которых мы могли нанимать. Мы могли нанять практически любого программиста с разным бекграундом и знать, что он освоит Go за пару недель. Со Scala всегда сначала есть кривая обучения в JVM, мир Java контейнеров, тёмная магия тюнинга JVM и так далее.
Новые разработчики входили теперь в игру за недели, а не за месяцы. Сейчас у нас большинство наших проектов написаны на Go, и последний сопротивляющийся Go программист буквально на днях написал свой первый Go проект и сказал мне следующее: «Ухты, я прочёл код библиотеки один раз и я знал, что она делает. Я прочёл код Scala-версии библиотеки 4 раза и до сих пор не понимаю до конца, как она работает. Теперь я понимаю, почему вы так запали на Go». Это был один из наших senior-разработчиков, который ранее работал в одной из крупнейших web-компаний мира. Весь этот процесс перехода на Go был целиком инициирован снизу нашими разработчиками, и был выбором команды.
Сейчас мы обрабатываем сотни тысяч сообщений в секунду и терабайты данных в день с нашими сервисами на Golang.
В этой статье я не хочу поругать Scala или ScalaZ(я люблю ValidationNel!), но хочу дать больше контекста из реального продакшн мира с более чем 7-летним опытом в двух компаниях. Я по-прежнему использую Scala, и мне нравится играться со Scalding. Некоторые из наших следующих амбициозных проектов будут скорее всего на Scala, но я больше не считаю, что делать его основным языком будет правильным выбором, особенно по мере роста команды. Go с тех пор стал моим языком по-умолчанию.
Go делает процесс разработки слишком простым.
![](https://habrastorage.org/files/42f/3d2/31f/42f3d231f76744b086ddc07c1382b4b0.png)