Как стать автором
Обновить

Go vs Python. Виталий Левченко

Время на прочтение15 мин
Количество просмотров58K

Предлагаю ознакомиться с расшифровкой доклада Виталия Левченко Go vs Python


Go — волшебное слово, решение всех проблем продакшна разом и одновременно негодная технология без эксепшнов. Истина посередине, поэтому поговорим о конкретных примерах:


  • asyncio vs горутины;
  • производительность узких мест;
  • лаконичность vs простота кода;
  • порог входа;
  • тулинг и паттерны поиска проблем и оптимизации производительности;
  • обслуживание в продакшне.



Я буду рассказывать про Go, потому что я на Go пишу примерно с 2012 года, а на Python я уже даже перестал писать. Я думаю, что я акцентирую внимание на том, что не очевидно. Моя риторика по поводу Go обычно довольно простая, что-то в духе «бросайте свой язык программирования и пишите на Go». Тут я надеюсь выжить до конца конференции, поэтому буду чуть помягче.


Собственно, почему я это всё делаю? Потому что я продвигаю Go с 2012 года, делаю Go MeetUp’ы с 2014, делаю кучу сервисов на достаточно большие нагрузки.



То, с чего вообще начинаю сравнение языков – это бенчмарки.


С бенчмарков вообще принято сравнивать. Если начинать холивар, то говорят: «Вот у нас есть мега бенчмарк, дергаем http, собственно, одно быстрее, другое медленнее». И вот так устроена половина холиваров в интернете уж точно. Мы не будем исключением, возьмём http. На самом деле возьмем просто бенчмарк, который сделали прекрасные люди из techempower.com/benchmarks/. У них http и довольно простенький формат в духе веб-приложения, достать 16 текстов из базы данных, отрендерить и выдать по http.



Они тестируют на довольно неплохом железе, на 14 ядрах, с гипертрейдингом.



И выдают следующие цифры. Собственно, 329 000 запросов в секунду переживает Go со специальным модулем для http, без специального модуля на нативном http он переживает 180 000 запросов в секунду. Это больше, чем перемалывают обычные сетевые карты.



С Python все гораздо грустнее. 65 – 70 тысяч запросов это специализированные фреймворки, для того, чтобы отвечать быстро.



А если берем django, всё ещё грустнее. Мы видим разницу больше, чем на порядок, то есть в 5 раз разница идёт со специализированным фреймворков, в 5-6 раз идёт разница с http, и django гораздо медленнее, ну и все остальные Twisted и прочее.



На самом деле имеет смысл сравнить latency, потому что это часто более важно. Я работал в рекламе, в стриминге. Там было важно. Если задержка больше 100 миллисекунд, то пользователи уже начинают жаловаться, что подтормаживает.



Фишка в том, что Python оказывается вполне с адекватными цифрами с latency, т.е. 7 миллисекунд на ответ на технагрузку это прямо хорошо. Но больше всего меня удивил django.



Latency у django получилось меньше, чем у Go. Если возьмёте в руки калькулятор и просто разделите одну цифру на другую, то есть вот эти 14 тысяч запросов в секунду, 28 ядер и 2 миллисекунды, оно поделится ровно (2ms 14,000req/s = 28 cores 1). Django отвечает без накладных расходов. Я к тому, что на самом деле все не так плохо, как показалось с самого начала.



Следующий момент, который сравнивается в бенчмарках, те люди, которые более-менее прошаренные, как работают приложения, это аллокации. Собственно, в чём суть? Нам периодически из кэша надо доставать кучу данных, например из redis или базы данных. Скажем, мы достаем 10 000 объектов по 100 полей, такие обычные ситуации, то есть, скажем, 10 раз по 1000 объектов достали и как-то их пережевали. В json это какие-то смешные 20 мегабайт, а то и 10 мегабайт.



Мы достаем из redis данные за долю миллисекунды, сеть их приняла за долю миллисекунды, а после этого Python их переживал ещё 200 миллисекунд. Осознайте эту дельту в цифрах. Больше того, после этого обработать эти данные будет стоить 10 миллисекунд в худшем случае. Аллокация – это реально дорого. Но фишка в том, что Go не сильно быстрее, но в Go есть другая штука, называется «кэш в памяти», мы можем просто этот кэш засунуть в память, не дергать его из базы, не дергать его из редиса, а просто брать и использовать.



Но мы можем попробовать использовать multiprocessing в Python. Дальше увидеть то, что обновление этого объекта в памяти, это 2 секунды, в течение которых приложение не может доставать из кэша ничего. То есть каждое обновление элемента кэша — это фриз приложения на 2 секунды. И вот это вот, это не в тупую запись, это просто перезапись объекта, то есть dict-update или что-то в таком духе.



Поэтому мы можем память не шарить, а просто держать ее в памяти локального приложения. Но дальше мы получаем очень грустную историю, если нам объектов нужно хранить много, скажем, 10 Гб в целом приложении, то мы получаем грустную историю, нам на 28 ядер нужно 280 Гб памяти. И это нерешабельная проблема в Python. Если вам по каким-то причинам нужно перемалывать хоть сколько-то значимое количество объектов, то Python просто не про вас.



И еще один важный момент: если вы всё-таки делаете 28 приложений, то есть вы запустили multiprocessing и крутите. Вы хотите сделать общие счётчики, например, метрики считать, просто какие-то счётчики. Выясняется, что сохранять в redis будет стоить 0,2 миллисекунды на каждый запрос. В случае Manager.Value плюс-минус такие же цифры, т.е. если мы в общую память сохраняем. Плагин Prometheus для счётчиков используют mmap и merged их на живую. Я не до конца понимаю, почему это работает и не падает по дороге. То есть он просто берёт на каждый процесс mmap файл и после этого без всяких mutex просто берет и merged. Это выглядит страшно, но по виду работает.



В Python в 2018 году появилась нормальная асинхронность Async/Await.



Логика вот какая. Я веду мысль к тому, что есть кейс, с которого я начинал знакомство с Go. Он выглядел примерно следующим образом, у нас были просто очереди в TopFace, они перемалывают какие-то лайки, запросы, сообщения, обработку подарочков. Технически это просто очереди, которые перемалывают демоны. Они упираются в кучу запросов в базу, в какую-то арифметику на этих данных и ЦПУ.


Представим, что у нас на машинке те самые 14 ядер. Как вы думаете, сколько воркеров надо запустить, чтобы эффективно утилизировать ЦПУ?


На самом деле, действительно, зависит от ситуации. Реальная цифра порядка 100-150-200, в зависимости от того, насколько быстро базы отвечают, и это в случае, если мы не используем нормальные goroutine и асинхронность. Больше того, если у нас база начинает отвечать медленнее, у нас ЦПУ не догружено, если база отвечает быстрее, у нас процессор оказывается перегружен на 200 потоках и машинка перестает отвечать хоть как-то. Поэтому нужны goroutine, поэтому нужно эффективное использование каждого ядра в таком формате.


Почему это важны goroutine в этом контексте? Мы можем запустить 200 потоков, которые просто что-то делают, а можем запустить 100 потоков, а можем 14, и по-простому что они делают во время запроса в базу? Если у нас goroutine, во время запроса в базу, она обрабатывает другие потоки, если у нас не goroutine, то просто thread залочен и все. Поэтому в случае goroutine мы хоть как-то это утилизируем. Этим Go крут. Потому что мы просто запускаем приложение. Оно просто скушает все ЦПУ. Поэтому переходите на 3.7, если у вас многопоточное приложение и вы упираетесь в ЦПУ.



В принципе по асинхронности самое важное, что есть в Go, это обработка в scheduler. Она сделана хитро. То есть просто syscall при каждом вызове отдают goroutine в scheduler с пометкой, что она не занимается ничем полезным, и возвращает из scheduler, когда syscall заканчивается. У нас в контексте 14 ядер, будет запущено ровно 14 goroutine, которые не в syscall, ну или меньше, если ядер физически меньше. Это работает, причем работает магический круто, т.е. вы просто запихнули какие-то goroutine, они что-то делают, они включаются в базу, на диск, еще что-то, ЦПУ утилизируется нормально, и ничего не блокируется, потому что все блокировки, они в первом пункте.


С mutex аналогично, но поскольку они в нативной библиотеке, стандартной, все проработано и точно так же работает.



На самом деле в Asyncio всё похоже. Точно также, если идёт запрос в сеть, он просто передается в Scheduler, который разруливает ее с какими-нибудь kqueue, epoll. Это красиво работает, это относительно синхронно на текущий момент выглядит, не так, как у Go. Но с Async/Await это хоть как-то хорошо.



Беда в том, что не все функции не блокирующие. Это приводит к грустной истории. Вот мы описали честный поток Async/Await. А потом внутри случайно вызвали функцию, которая что-то блокирует. Чем больше приложений, тем больше вероятность, что мы такую функцию вызовем. У нас весь runtime встал целиком, пока функция не разблокируется.



Поэтому нужно использовать внешние библиотеки, которые Asyncio точно поддерживает. Мы открываем aio-libs, которые пишут 11 баз данных. У них, правда, есть всякие интересные проблемы, например оно падает на каких-то хитрых ответах или при попытке сделать Close, но оно делает вид что работает. Там нет важных для production баз типа Aerospike, и на самом деле там не хватает ряда полезных таймаутов. Это проблема. Если у вас есть какой-то таймаут базы, который вы не можете поставить, и этот таймаут сработает, то у вас горутина сдохнет на время таймаута, и вам нужно либо снаружи обрабатывать каким-то странным образом.



В Python нет нормального способа коммуникации между thread. В Go это есть из коробки. Вот за это реально надо любить Go. Мы можем честно взять и уведомить все goroutine, в которых происходят какая-то обработка, и сказать им: «Надо завершиться». Например, мы делаем Graceful shutdown. Мы шлем сигнал, все аккуратненько завершаются и после этого мы останавливаем приложение. В случае Python нужны либо поддержки соответствующих обработчиков, то есть поддержка внутри http, внутри net и других библиотек. И всё равно это неудобно. Вы всё равно пробрасываете огромное количество каких-то вещей. У вас нет гарантий, что он завершится. А в Go здесь прям просто, из коробки, вы просто делаете канал, в который вы шлете сигнал о том, что приложение завершается и обработчик завершается.



Больше того, Select в Go еще крут тем, что мы хотим читать сразу из 5 разных потоков. Например, у нас есть 5 разных продюсеров, они пикируют 5 разных видов данных, их надо обрабатывать по-разному, мы их можем просто взять и обрабатывать всех по-разному. В случае Python нам их нужно объединять в единый queue, то есть сперва объединить с потерей типов, потом обратно разъединить с нахождением типов, потом узнать, что нужно читать в двух разных местах и всё сломается. В Go такого нет, и это круто.



Теперь перейдем к самой, наверное, холиварной вещи в контексте Python и Go. Люди говорят: «Я пишу в DataScience, я всякие модельки рассчитываю, умножаю их и так далее».



На самом деле DataScience, это здорово, и за него хорошо платят, поэтому заниматься DataScience это здорово.



Но в Go на самом деле все не так уж и плохо. То есть более или менее популярные библиотеки уже сделаны и сделаны нормально. Больше того, если вы в какой-то момент начинаете упираться в ваши библиотеки, например, у вас обучение работает слишком медленно или оно вам нужно в других параметрах, или вам нужно онлайн-обучение, сразу выясняется, что ничего готового нет, надо делать самим.


И в этот момент выясняется, что то, что вы сделаете, может получиться в разы быстрее, чем в библиотеке Python, причём вы не сильно напрягались.



А если напряглись, то получилось сильно быстрее. Есть пример, SсiKit — расчёт рекомендаций. Это то, что называется коллаборативной фильтрацией, когда у нас есть пользователь, который фильмы лайкает. Мы хотим найти похожих пользователей. Исходя из этого оценить для пользователя, как он оценит текущий фильм. Есть Sсikit. Есть Surprise библиотека, которая умеет SVD. Там есть 2 алгоритма, SVD, который обсчитывает модельку 2 минуты и SVD++, который обсчитывает эту модельку, конкретную, за 3 часа. Как вы думаете, за сколько Go считает SVD++?



На самом деле 2 минуты. Если вы берете библиотеку, которая хорошая, уровня enterprise, она много где используется, вы можете в ряде случаев увеличить производительность на два порядка. Если вам хочется улучшить текущую производительность там, вы можете просто взять библиотеку с поддержкой AVX2 и получить прирост ещё на 20% для обычного SVD. У меня есть знакомая, которая, собственно, использует Go именно для конкретного обучения, просто взяли и переписали нужную генерацию из Spark на Go. Это стоило им в разработке пары недель.



И тут мы подходим к тому, ради чего с Go хорошо делать, когда мы говорим про производительность, это всяческая оптимизация. Мы берём Go, пишем неоптимизированный код. Если мы хотим, чтобы оно стало работать еще быстрее, мы просто вызываем профилирование. И оно начинает работать в 2 раза быстрее или в 10 раз быстрее, если мы что-то не так сделали.



Профайлинг делается в Go в одну строчку. Просто добавляем импорт pprof и он выкидывает данные наружу по http. Эту ссылочку можно открывать прямо в браузере или через нативную утилиту pprof.



Она показывает, что в конкретных либах, в том числе системных, в том числе какие-то syscall тормозят. Она говорит: «Тормозит Garbage Collector» или «Тормозит конкретный mutex», или «Тормозит конкретная ваша логика».


Прямо из этого pprof можно получить list func. Он построчно покажет на каких строчках она сколько времени проводит.


Дальше мы можем вызвать disasm этой функции и ещё увидеть, на каких ассемблерных строчках оно так себя ведет.



Общий профайлинг выглядит примерно вот так. Это просто визуализация времени вызова.



Есть FlameGraph, который внезапно в Python появился раньше.



И вот то, что я говорил, можно построчно показать, как это по миллисекундам работает.



Мы можем взять флаг gcflag -S и получить исполняемый ассемблерный код прямо на живую.


Можем поставить gcflag -m при компиляции и после этого нам pprof будет выдавать информацию по Inline функциям локации на хипе.


Мы можем взять и переписать функцию на C или Ассемблере. После этого понимая, что происходит. Например, мы видим какую-нибудь функцию, которая работает 8% времени, мы просто берем и переписываем и 8% времени превращается в 10% времени.


Мы можем сравнить 2 профайлинга. Крутость Go в том, что на этом основана разработка Go как такового. То есть вот разработчики реально каждый раз приходят и говорят: «У нас раньше было http c такой скоростью работала, вот в этой версии с такой скоростью», прямо циферки показывают. И это каждый раз, это уникально из того, что я видел по языкам, это именно когда разработчики всерьёз заморочены и отчитываться по оптимизации.



Pprof умеет умеет показывать информацию про память, блокировки, mutex, stacktrace, tracing живой. Например, вы запустили и на живую можете посмотреть, как это работало последние 5 секунд. Можете даже отслеживать, что вы из собственного треда запускаете, если вы по каким-то причинам запускаете много, это можно отловить.



Есть build-race — актуален, как только вы начинаете работать во много потоков. Например, вы просто пытаетесь в одну и ту же переменную писать параллельно, или писать и считать. Build-race соберет приложение с поиском race conditions, он будет работать в 4 раза медленнее, но при этом он вам отчитается, что вы работаете с блокировками не так или просто работаете с памятью не так.


Можно еще тестировать память, можно тестировать сколько локаций происходит и так далее, это полезно, когда вы начинаете работать с GC.



На самой деле самое интересное, это разработка.



Крутость Go в том виде, в котором я с ним работал, это то, что мы апгрейдим Go, вот реально с 1.0 на 1.1, с 1.1 на 1.2, с 1.2 на 1.3 и так далее, с 1.11 на 1.12, и у вас он просто работает, то есть работает ваш код, работают все библиотеки, без единой адаптации. Это было у меня с 2012 года.


И вторая вещь, которая крутая. Она спорная, потому что долгое время не было нормальной работы с зависимостями. Когда мы делаем go get и библиотека в Go достается из мастера и он летит сразу всем разработчикам, которые используют эту библиотеку. Это минус. Но в связи с этим, мэйнтенеры библиотек дисциплинированы. Они знают, что если они что-то поменяют обратно не совместимо, то существенная доля разработчиков будет сильно недовольна, причём очень сильно. Если первые годы это было неожиданно, то сейчас это стало привычкой.


Если делается обратная несовместимость, то это делают другой пакет/репозиторий. И оно так работает. Оно так прижилось. Реально обратную совместимость не портят, за очень редким исключением.



На моем пути, вот прям в живом соседнем проекте, взяли Python, обновили с 3.6 на 3.7 и он не скомпилировался. Написал, что какие-то QT библиотеки нормально не работают.


Берём библиотеки Python и выясняем, что мажорная версия ломает обратную совместимость, причем ломает так, что это чинить неоправданно дорого.


Возможно у вас другой опыт, но я это просто на живую видел в соседних проектах, меня это каждый раз расстраивало.



В Go с зависимостям всё даже повеселее, чем в Python, потому что не принято зависеть от системных либ, принято, если вы что-то используете в системных либах, принято это писать самостоятельно.


Я вижу скептические лица, но на самом деле это хорошая идея. Потому что после этого оно переносимо. Если библиотека заявила, что она поддерживается на Mac, Windows, Linux и еще на каком-то телефоне, то она там действительно поддерживается. И не надо доставлять 5 библиотек непонятных версий.


В версии Golang 1.12 появился Go Mod именно как дефолтный инструмент для работы с зависимостями. Всё стало здорово. Мы просто вызываем go install. Он сам просто заполняет файл go.mod при вызове go get. Вам не нужно делать pip freeze и прочее. Нет таких проблем, если забыть сделать pip freeze.


Зависимости по умолчанию не хранятся вместе с пакетом. Нет директории аналогичной virtualenv, в которой лежит половина интернета, как в случае с какими-нибудь node_modules. В Python этого поменьше, но всё равно такие существенные директории получаются, если много чего используете.


Golang все зависимости складывает в общий кэш для пользователя и там их версианирует, подписывает с ключиками. Можно не бояться того, что мейнтейнер возьмет и перепишет что-нибудь, потому что это будет видно по контрольным суммам.


В Go библиотеки не пытаются что-то делать с runtime: GC паузы перенастраивать, так, чтобы GC вызвался или, наоборот, GC не вызывался, или пропатчить какие-то функции системные. Такого ничего нет.



Своя библиотека в Go. Вы просто берете свою директорию, копируете в соседнюю директорию, там её инициализируете, заносите прямо в гитхаб и она сразу работает. Больше сразу на godoc.org у вас будет документация к вашему проекту прямо из коробки.


Если вы, например, патчите чужую библиотеку, у вас PR приняли, и вы сразу можете пользоваться результатами. Вам смержили PR минуту назад, вы уже через go install получаете пропатченную зависимость.


Если вам по каким-то причинам это не нравится. Например, мержат медленно или ещё что-то, вы просто берете и используете свой форк, что делается реально в одну команду.



Раз уж мы заговорили про удобства, то прикольно в Go, это то, что есть документация.



Вы вызываете godoc -http=:6060 и у вас прям вся документация по Go и всем пакетам прямо в ноутбуке и работает в режиме самолета. Я реально в самолёте писал код. Система документации реально одна, то есть нет 10 способов, как это делать через какой-нибудь pydoc или sphinx. У нас godoc, он стандартный, он везде работает.



Теперь идём к самому интересному. Кто из вас слышал, что в Go нет Exception? Так вот это неправда, они там есть и называются panic.



Есть прекрасный кейс от Никиты Соболева, о том, что просто берем функцию, которая не знаю, дергает интернет, спрашивает пользователя и пытается вернуть этого самого пользователя наружу. Как вы думаете, в скольких местах это может сломаться с Exception? Во многих. И очень хорошо бы Excepton обработать, потому что они разные. Их нужно наверх пробросить с разными кодами и так далее. В идеале ещё и как-то перемолоть по-разному.



На Go это просто делается выводом ошибок. Функции, которые могут вывести ошибку, они последним параметром выводят ошибку и мы можем ее обработать. Делаем http get. Если вернулась ошибка, то возвращаем ошибку наверх, с какой-нибудь оберткой.



Следующий пример. Обработка статус кода, который внезапно не таймаут. Нам сервер ответил корректно 500 http code. Это меня каждый раз удивляет в http либах. Ответ http code 500 считается корректным, а 400 это точно корректный. Ну и собственно дальше, декодировать и обратно вывести. Вместо неявного Excepton у нас появились явные ошибки, по которым мы хотя бы видим, что сломалось и в каком месте.



Но здесь же можно внимательно подумать и обработать это. Например, не вернуть ошибку и сказать, если внешний сервер лежит, то у нас нет пользователя.



Кодировки. Это забавная штука, в Go сразу UTF-8, а в Python с 3.7 тоже сразу UTF-8, но на практике не все утилиты/библиотеки об этом догадываются.



Если вы опытный бэкендер, вам без разницы на чём писать, на Python, Ruby, elixir, Go, Java. Если это не C++, то точно на чём угодно.



Есть гораздо более важный показатель – зарплата. Да, мы берём статистику "Мой круг" за вторую половину 2018 года. Они говорят, что 75 процентиль зарплаты разработчика Python 150 тысяч рублей, 90% процентиль – 185 тысяч рублей. У "Get It" есть бот в телеграме. Они говорят, что Senior разработчик Python получает 175 – 200 тысяч рублей.


StackOverFlow, который тоже собирал статистику по 100 тысяч пользователей по всему миру, они говорят 98 тысяч долларов за Python.



С Go все куда веселее. Собственно "Мой круг" дают 180 – 225 тысяч рублей, "Get It" дает 205 – 250 тысяч рублей, StackOverFlow 110 тысяч долларов в год. В целом + 20% за то, что вы пишете на Go.



Python лучше, если же вам на самом деле нужно быстро запустить приложение. Если вы делаете в Data science и вас устраивает то, что получается, тоже здорово.



Если вы упираетесь в скорость ответов, в latency ответов, в память, которую надо хранить или скажем вам нужно с диском аккуратно работать. Внезапно выяснится то, что Go существенно лучше. Например, когда выяснится, что сеть медленная.


Go хорош, когда вам важна простота operation. Вы просто скопировали/задеплоили бинарник в production и забыли про него. Вы просто обработали все ошибки, поэтому вы знаете какие ошибки есть.


Почему зарплаты в Go больше? Потому что задачи более сложные. Это более интересные задачи и за них дают больше денег



Вопрос: Какой интерпретатор питона вы использовали в бенчмарках?


Ответ: СPython. По первому бенчмарку, который http. Там PyPy использовался. Он не сильно лучше. Где-то хуже, где-то лучше.


Вопрос: Вопрос относительно скорости разработки на Python и Go, потому что всё-таки Python считается более высокоуровневый и вот были какие-то исследование по данной теме?


Ответ: Я специально искал такие исследования, я их не нашёл. Я могу поделиться своим опытом по этому вопросу. Внезапно скорость разработки, она ограничивается тем, с какой скоростью мы можем воспринимать текст, который написан, то есть вот скажем 90%, 80% времени мы читаем код, 10% пишем. И здесь более критично не количество букв, а сложность кода. Если вы сделали лямбду лямбду в лямбде. Это читать тяжело.


Код Go простой. Его тяжело сделать по-разному. И это замечательно. В go действительно реализован единый хороший формат. И поскольку он реализован, вы с первого раза считываете паттерны, а потом просто читаете код с листа быстро. Исходя из этого скорость разработки сравнимая.


Вопрос: Холиварный вопрос, почему еще не все на Go?


Ответ: Люди консервативные. Компании еще более консервативные. Если взять рынок, который действительно конкурентный, например, OpenSource. То мы видим что все инфраструктурные утилиты пишут на Go с 2014 года: Prometheus, influxdb, docker, Kubernetes. Все сервисы, которые начинает упираться в вышеуказанные проблемы, например в DropBox или CloudFleer, то они пишут на Go. В OpenSource инфраструктурные утилиты исключительно на Go пишут.


Вопрос: Ты сказал, что зарплаты самое важное, но если пойти на тот же "Мой круг", окажется, что на Scala и на Elixir платят больше, это значит, что мне надо пойти туда, а не в Go?


Ответ: В 2018 году Go стал более дорогим. Больше того, есть американский обзор по зарплатам, который говорит, что вот именно из скиллов, по языкам, Go самый дорогой.


Вопрос: Ты упомянул две вещи, которые мне кажется немножечко взаимоисключающими. Ты сказал про читаемость кода. Любая обработка ошибок эксплицитная. Она замыливает глаз. Ты глядя, на хороший написанный код на С, понимаешь что он состоит примерно из 90% обработки потенциальных ошибок. А сама логики размазана. Ты пишешь программу на Go, проверяешь в ней все ошибки исходя из слайда вручную. Каждая ошибка явно эксплицитно проверяется и дальше пробрасывается. И при этом ты говоришь про чистоту и простоту написания кода. Когда мы говорим, про то, что мы пишем код на Python, в котором мало обработки ошибок, то мы соберём stackstrace в Sentry, посмотрим всё что было, отберем то, что критичное и с этим будем разбираться. При этом код остаётся гораздо меньше. Чем меньше код, то в нем явно ненужной специфичной обработки ошибок, тем он будет более читаем. И как это совмещается?


Ответ: Это хороший вопрос. На самом деле это моя личная боль. Это больно, то есть эта ситуация сейчас решается. Вообще, есть несколько паттернов, которые позволяют избежать обработки ошибок. То есть заменить обработку ошибок на паники, фактически аналогов Exception.


Есть способы как это обработать. Например, сделать так, что функция в самом начале делают проверку в структуре.


Вопрос: Попытаюсь как-то подытожить, это сводится к сноровке по обращению с языком?


Ответ: Просто приходит человек. Он видит как это написано и код по аналогии. Если код изначально был написан нормально, то, он пишет нормально.


P.S. Телеграм чаты:


golang — Новости по языку программирования Go, ссылки на статьи и интересные проекты


Golang RU — Чат про Golang


Golang Jobs and Freelance — Jobs and freelance for golang developers

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 43: ↑26 и ↓17+17
Комментарии39

Публикации

Истории

Работа

DevOps инженер
41 вакансия
Data Scientist
78 вакансий
Go разработчик
117 вакансий
Python разработчик
119 вакансий

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань