<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Ilia Ushakov</title><author><name>Ilia Ushakov</name></author><id>https://teletype.in/atom/ushakov</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/ushakov?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/ushakov?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-05T14:59:36.001Z</updated><entry><id>ushakov:go-tags-in-tests</id><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov/go-tags-in-tests?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><title>Разделение тестов с помощью тегов сборки</title><published>2021-10-27T20:56:04.836Z</published><updated>2021-10-27T21:00:33.783Z</updated><summary type="html">В Go есть внутренний механизм для логического разделения тестов в зависимости от некоторых условий, в том числе условий на операционную систему или тип CPU. Так, например, можно отделить юнит тесты от интеграционных или от smoke тестов.</summary><content type="html">
  &lt;p id=&quot;k3fo&quot;&gt;В Go есть внутренний механизм для логического разделения тестов в зависимости от некоторых условий, в том числе условий на операционную систему или тип CPU. Так, например, можно отделить юнит тесты от интеграционных или от smoke тестов.&lt;/p&gt;
  &lt;h2 id=&quot;uewI&quot;&gt;Что такое теги сборки?&lt;/h2&gt;
  &lt;p id=&quot;rPUJ&quot;&gt;Тег сборки - это комментарий  в начале go-файла, который указывает компилятору, как стоит собирать этот конкретный файл.&lt;/p&gt;
  &lt;p id=&quot;hdK2&quot;&gt;Например, при таком теге файл будет включен в сборку только в том случае, если компиляция выполняется под линукс (GOOS=linux)&lt;/p&gt;
  &lt;pre id=&quot;Ll47&quot;&gt;// +build linux

package mypackage
...&lt;/pre&gt;
  &lt;p id=&quot;9o0n&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;o6Eh&quot;&gt;Тег сборки должен быть расположен в начале файла, а после строки с ним должна быть пустая строка.&lt;/p&gt;
  &lt;p id=&quot;Fod9&quot;&gt;Также можно использовать оператор отрицания &lt;code&gt;!&lt;/code&gt;. Таким образом, файл с тегом &lt;code&gt;// +build !linux&lt;/code&gt; будет включен в сборку на всех платформах, кроме linux.&lt;/p&gt;
  &lt;p id=&quot;Hbrj&quot;&gt;В тегах может быть несколько условий. Если условия расположены на одной строке, то они комбинируются через оператор OR. А если на нескольких строках, то через AND.&lt;/p&gt;
  &lt;pre id=&quot;wbhB&quot;&gt;// +build linux darwin
// +build amd64

package mypackage
...&lt;/pre&gt;
  &lt;p id=&quot;gYcr&quot;&gt;В примере выше файл будет включен в сборку только под &lt;em&gt;linux/amd64&lt;/em&gt; или &lt;em&gt;darwin/amd64&lt;/em&gt; платформы.&lt;/p&gt;
  &lt;p id=&quot;bmsz&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;vM0n&quot;&gt;Разделение тестов&lt;/h2&gt;
  &lt;p id=&quot;LEgC&quot;&gt;Через теги сборки можно разделять разные виды тестов.&lt;/p&gt;
  &lt;p id=&quot;5b97&quot;&gt;Рассмотрим 2 файла тестов:&lt;br /&gt;&lt;em&gt;myfile_test.go:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;52Vy&quot;&gt;package mypackage

import &amp;quot;testing&amp;quot;
...&lt;/pre&gt;
  &lt;p id=&quot;IMIR&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Xy3g&quot;&gt;&lt;em&gt;myfile_integration_test.go:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;jG0r&quot;&gt;// +build integration

package mypackage

import &amp;quot;testing&amp;quot;
...&lt;/pre&gt;
  &lt;p id=&quot;hQcI&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;3f6Z&quot;&gt;В файле &lt;em&gt;myfile_test.go&lt;/em&gt; будут расположены unit тесты, а в &lt;em&gt;myfile_integration_test.go&lt;/em&gt; - интеграционные (более медленные).&lt;/p&gt;
  &lt;p id=&quot;cI32&quot;&gt;Поэтому при запуске тестов через &lt;code&gt;go test&lt;/code&gt; запустятся тесты только из &lt;em&gt;myfile_test.go&lt;/em&gt;. А если нужно запустить тесты из &lt;em&gt;myfile_integration_test.go&lt;/em&gt;, то надо добавить флаг &lt;code&gt;—tags&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;dUGf&quot;&gt;&lt;code&gt;go test --tags=integration&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;aTYo&quot;&gt;Важно понимать, что при запуске &lt;code&gt;go test --tags=integration&lt;/code&gt; так же запустятся unit тесты. Чтобы такого не произошло, надо добавить отрицание в теги сборки unit тестов.&lt;/p&gt;
  &lt;p id=&quot;QPnB&quot;&gt;&lt;em&gt;myfile_test.go&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;4MKr&quot;&gt;// +build !integration

package mypackage

import &amp;quot;testing&amp;quot;
...&lt;/pre&gt;
  &lt;p id=&quot;zH2F&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;1M1z&quot;&gt;Итог&lt;/h2&gt;
  &lt;p id=&quot;jt2W&quot;&gt;Есть несколько причин такого разделения тестов:&lt;/p&gt;
  &lt;ol id=&quot;287F&quot;&gt;
    &lt;li id=&quot;eVot&quot;&gt;Интеграционные тесты значительно медленней unit тестов, поэтому их обычно стоит запускать только после успешного запуска unit тестов&lt;/li&gt;
    &lt;li id=&quot;rsyL&quot;&gt;Компиляция под разные платформы&lt;/li&gt;
    &lt;li id=&quot;F29l&quot;&gt;Smoke тесты, запускаемые на production приложение после деплоя.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;WcU1&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;E0H3&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;BLzJ&quot;&gt;Источник: &lt;a href=&quot;https://mickey.dev/posts/go-build-tags-testing/&quot; target=&quot;_blank&quot;&gt;https://mickey.dev/posts/go-build-tags-testing/&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>ushakov:ceph</id><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov/ceph?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><title>Хранилище ceph</title><published>2021-09-19T11:19:23.121Z</published><updated>2021-09-19T11:19:23.121Z</updated><summary type="html">Очень хорошая статья про хранилище ceph на хабре</summary><content type="html">
  &lt;p id=&quot;pvUo&quot;&gt;Очень хорошая статья про хранилище ceph на &lt;a href=&quot;https://habr.com/ru/post/313644&quot; target=&quot;_blank&quot;&gt;хабре&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;KX0A&quot;&gt;Если коротко: &lt;/p&gt;
  &lt;blockquote id=&quot;YNpH&quot;&gt;Ceph — это программно определяемая распределенная файловая система с открытым исходным кодом, лишенная узких мест и единых точек отказа, которая представляет из себя легко масштабируемый до петабайтных размеров кластер узлов, выполняющих различные функции, обеспечивая хранение и репликацию данных, а также распределение нагрузки, что гарантирует высокую доступность и надежность.&lt;/blockquote&gt;

</content></entry><entry><id>ushakov:goproxy</id><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov/goproxy?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><title>GOPROXY</title><published>2021-09-19T11:05:40.073Z</published><updated>2021-09-19T11:05:40.073Z</updated><summary type="html">Начиная с версии Go 1.13, стандартный менеджер пакетов в Go - это Go modules. Вместе с ним появилась переменная окружения GOPROXY, которая определяет, откуда будут скачиваться пакеты. </summary><content type="html">
  &lt;p id=&quot;8Cx7&quot;&gt;Начиная с версии Go 1.13, стандартный менеджер пакетов в Go - это Go modules. Вместе с ним появилась переменная окружения GOPROXY, которая определяет, откуда будут скачиваться пакеты. &lt;/p&gt;
  &lt;p id=&quot;DDof&quot;&gt;Посмотреть текущую конфигурацию:&lt;/p&gt;
  &lt;pre id=&quot;Clr2&quot;&gt;~ ❯ go env GOPROXY
https://proxy.golang.org,direct&lt;/pre&gt;
  &lt;p id=&quot;91jE&quot;&gt;В переменной GOPROXY будут указываться источники через запятую, откуда go будет пытаться скачать необходимый пакет. Если первый источник ответит 4xx, то go попробует скачать пакет по следующей ссылке. &lt;/p&gt;
  &lt;p id=&quot;5rO7&quot;&gt;Direct указывает, что код надо загрузить по прямой ссылке из VCS. То есть ровно по той ссылке, как пакет импортируется в коде. &lt;/p&gt;
  &lt;p id=&quot;RXc0&quot;&gt;Однако, загружать пакеты с VCS может быть не всегда безопасно. &lt;/p&gt;
  &lt;p id=&quot;u46l&quot;&gt;Кто-то может внести вредоносный код в новых коммитах, или даже если вы строго зафиксировали версию пакета, с которым хотите работать, злоумышленник может изменить текущую версию кода через  &lt;code&gt;git push --force&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;i5pF&quot;&gt;Сейчас по умолчанию в GOPROXY устанавливается &lt;a href=&quot;https://proxy.golang.org&quot; target=&quot;_blank&quot;&gt;https://proxy.golang.org&lt;/a&gt; как прокси и работает как кеш. То есть если в proxy.golang.org нужного пакета не найдется, то он его скачает и сразу же отдаст нам. Этот кеш гарантирует, что код не будет изменен. &lt;/p&gt;
  &lt;p id=&quot;swa8&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;4414&quot;&gt;Источники:&lt;/p&gt;
  &lt;p id=&quot;KGjr&quot;&gt;&lt;a href=&quot;https://golang.org/ref/mod#goproxy-protocol&quot; target=&quot;_blank&quot;&gt;https://golang.org/ref/mod#goproxy-protocol&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;n6ZU&quot;&gt;&lt;a href=&quot;https://jfrog.com/blog/why-goproxy-matters-and-which-to-pick/&quot; target=&quot;_blank&quot;&gt;https://jfrog.com/blog/why-goproxy-matters-and-which-to-pick/&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>ushakov:logging-levels</id><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov/logging-levels?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><title>Уровни логирования</title><published>2021-09-18T21:54:31.082Z</published><updated>2021-09-18T21:54:31.082Z</updated><summary type="html">У логов следует использовать разные уровни, так будет легче фильтровать и исследовать проблему по логам. </summary><content type="html">
  &lt;p id=&quot;WN4I&quot;&gt;У логов следует использовать разные уровни, так будет легче фильтровать и исследовать проблему по логам. &lt;/p&gt;
  &lt;p id=&quot;JgUA&quot;&gt;Так же можно будет настроить алерты только на определенный тип сообщений, и получать уведомления, когда в системе произошла серьезная ошибка. &lt;/p&gt;
  &lt;p id=&quot;zqEh&quot;&gt;И можно будет настроить разный уровень сохранения/выводы логов. В таком случае при разработке можно включить вывод логов от &lt;em&gt;INFO &lt;/em&gt;уровня, а на проде важно сохранять только сообщения уровня WARNING и выше.&lt;/p&gt;
  &lt;p id=&quot;dpl0&quot;&gt;Ниже описаны основные уровни логов и причины их использовать:&lt;/p&gt;
  &lt;h2 id=&quot;vAMG&quot;&gt;ERROR&lt;/h2&gt;
  &lt;p id=&quot;U5L7&quot;&gt;В системе случилось что-то критичное, что влияет на бизнес процесс, на деньги, на пользователей. На такой тип ошибок должны быть настроены уведомления, чтобы даже ночью дежурные могли оперативно отреагировать на проблему. &lt;/p&gt;
  &lt;p id=&quot;e8rJ&quot;&gt;&lt;em&gt;Например:  Внешний платежный шлюз перестал отвечать на наши запросы&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;9iPM&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;1rob&quot;&gt;WARNING&lt;/h2&gt;
  &lt;p id=&quot;0ppE&quot;&gt;В системе произошла серьезная ошибка, но есть вероятность, что программа самостоятельно восстановится. При такой ошибке тоже надо уведомить дежурных, просто оперативная реакция не требуется. &lt;/p&gt;
  &lt;p id=&quot;TpNf&quot;&gt;&lt;em&gt;Например:  На наш запрос не ответил внешний платежный шлюз. Дальше retry система попробует повторить запрос еще несколько раз. И если шлюз так и не ответит, то упадет ошибка &lt;strong&gt;ERROR&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;pxmZ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;yayF&quot;&gt;INFO&lt;/h2&gt;
  &lt;p id=&quot;QdhM&quot;&gt;Произошло изменение в системе или в какой-то сущности. &lt;/p&gt;
  &lt;p id=&quot;I3sA&quot;&gt;&lt;em&gt;Например: &lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;SNFZ&quot;&gt;&lt;em&gt;1. Система поднялась на порту 8080&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;C8l7&quot;&gt;&lt;em&gt;2.  создан новый пользователь&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;bKg7&quot;&gt;&lt;em&gt;3. вывод по cron задачу&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;kAxv&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;OmEu&quot;&gt;DEBUG&lt;/h2&gt;
  &lt;p id=&quot;dKlH&quot;&gt;Служит для отладки приложения при разработке, или в случае, когда надо поймать что-то на проде. &lt;/p&gt;
  &lt;p id=&quot;rLT1&quot;&gt;&lt;em&gt;Например: текущее значение какой-то переменной&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;mhc5&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;yLNU&quot;&gt;TRACE&lt;/h2&gt;
  &lt;p id=&quot;2jsw&quot;&gt;Такой уровень логов нужен, чтобы отслеживать запросы внутри приложения.&lt;/p&gt;
  &lt;p id=&quot;clpO&quot;&gt;Например: &lt;/p&gt;
  &lt;ol id=&quot;KquL&quot;&gt;
    &lt;li id=&quot;Xa5d&quot;&gt;Пришел запрос на url /home&lt;/li&gt;
    &lt;li id=&quot;JKQi&quot;&gt;Завершили обрабатывать запрос на /home за 0.5 секунд&lt;/li&gt;
    &lt;li id=&quot;0aDr&quot;&gt;Начали/завершили обрабатывать метод&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;TJQk&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;slhO&quot;&gt;Источник: &lt;a href=&quot;https://reflectoring.io/logging-levels&quot; target=&quot;_blank&quot;&gt;https://reflectoring.io/logging-levels&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>ushakov:unit-tests-with-scenarios</id><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov/unit-tests-with-scenarios?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><title>Пишем unit тесты через сценарии</title><published>2021-09-18T20:11:47.377Z</published><updated>2021-09-18T20:13:37.222Z</updated><summary type="html">При таком подходе тест состоит из 3х частей:</summary><content type="html">
  &lt;p id=&quot;U0Lq&quot;&gt;При таком подходе тест состоит из 3х частей:&lt;/p&gt;
  &lt;ol id=&quot;21Jj&quot;&gt;
    &lt;li id=&quot;CpWh&quot;&gt;Состояние системы на момент запуска теста&lt;/li&gt;
    &lt;li id=&quot;SV3s&quot;&gt;Событие, которое изменяет состояние системы&lt;/li&gt;
    &lt;li id=&quot;2Spf&quot;&gt;Результат - то, что должно произойти/измениться&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;5dZF&quot;&gt;Для удобства предлагается разделить эти комментариями, чтобы не пытаться понять все через код. &lt;/p&gt;
  &lt;p id=&quot;16WM&quot;&gt;Обратите внимание, что assert&amp;#x27;ы выполняются только в третей части теста. &lt;/p&gt;
  &lt;figure&gt;
    &lt;script src=&quot;https://gist.github.com/ushakovme/274d12a54081388614a7e5d9a3e7ee87.js&quot;&gt;&lt;/script&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;F2DY&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;iLKk&quot;&gt;Названия тестовых методов является продолжением фразы:  &amp;quot;Что случается, когда ...&amp;quot; &lt;/p&gt;
  &lt;figure&gt;
    &lt;script src=&quot;https://gist.github.com/ushakovme/8473c016c839a946325601f422346aee.js&quot;&gt;&lt;/script&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;w9wY&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;HyQe&quot;&gt;Источник: &lt;a href=&quot;https://matthiasnoback.nl/2021/09/write-unit-tests-like-scenario&quot; target=&quot;_blank&quot;&gt;https://matthiasnoback.nl/2021/09/write-unit-tests-like-scenario&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>ushakov:multistage-docker</id><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov/multistage-docker?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><title>Собираем минимальный Docker образ для Golang приложений</title><published>2021-09-12T21:17:42.822Z</published><updated>2021-09-12T21:17:42.822Z</updated><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/7e/24/7e24f47e-172c-4e3f-b3ee-2736fef502c9.png&quot;&gt;Обычный докер образ Golang приложения занимает порядка 600mb. </summary><content type="html">
  &lt;p id=&quot;6KL0&quot;&gt;Обычный докер образ Golang приложения занимает порядка 600mb. &lt;/p&gt;
  &lt;p id=&quot;QddE&quot;&gt;Чтобы облегчить образ, надо использовать multistage build. Это когда сначала все собирается в один образ, а потом результаты сборки копируются в другой. А инструменты сборки и все лишнее не копируются. &lt;/p&gt;
  &lt;p id=&quot;Cka6&quot;&gt;&lt;/p&gt;
  &lt;figure&gt;
    &lt;script src=&quot;https://gist.github.com/ushakovme/a53c17d5f4f5c4c5eda56722f574ce05.js&quot;&gt;&lt;/script&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;eaL8&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;B3yw&quot;&gt;Так итоговый образ получился размером 4.3MB&lt;/p&gt;
  &lt;figure id=&quot;3HVC&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7e/24/7e24f47e-172c-4e3f-b3ee-2736fef502c9.png&quot; width=&quot;800&quot; /&gt;
  &lt;/figure&gt;

</content></entry><entry><id>ushakov:first-post</id><link rel="alternate" type="text/html" href="https://teletype.in/@ushakov/first-post?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=ushakov"></link><title>hi</title><published>2021-09-05T18:54:28.739Z</published><updated>2021-09-05T18:55:16.917Z</updated><summary type="html">jjjjj</summary><content type="html">
  &lt;pre id=&quot;ynZe&quot;&gt;$ git add articles/wizard-of-oz.txt
$ git commit -m &amp;#x27;wrote the wizard of oz.&lt;/pre&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;pj8I&quot;&gt;jjjjj&lt;/p&gt;

</content></entry></feed>