Яхья Картоев | Backend простым языком
367 subscribers
19 photos
1 video
28 links
Пишу про бэкенд и golang
Download Telegram
PostgreSQL timestamp.

TL;DR Всегда используйте для дат timestamp with time zone

Ситуация: В базе есть колонка updated_at, тип которой timestamp, а значение по умолчанию CURRENT_TIMESTAMP.

Проблема: Вычитываем значение этой колонки, сравниваем с time.Now(), и оказывается, что в колонке лежит время +3 часа по сравнению с тем, что дает гошный time. То есть в часовом поясе Москвы, притом без указания таймзоны, что лишает нас возможности перевести time в ту же часовую зону для корректного сравнения времен.

Неожиданно оказалось, что CURRENT_TIMESTAMP при конвертировании в timestamp сохраняет текущее время не в UTC, как можно было бы ожидать, а в часовом поясе клиента, который инициировал запрос (теряя при этом инфу о таймзоне). А если клиентский он не знает, то в часовом поясе сервера, на котором он находится.

Решение:
- Если у вас маленькая база, то накатить миграцию с изменением типа колонки
- Если база большая и не хочется мучаться с аккуратным переездом на новый тип, при сохранении даты явно указывать таймзону timezone('UTC', CURRENT_TIMESTAMP)
- В будущем всегда использовать timestamp with time zone

______________________________
@Backend простым языком
👍8
Хочешь добавить прогон юнит-тестов в гитлабе при создании мерж-реквеста и подозреваешь, что джоба не будет падать, если тесты не прошли
Раньше:
- Гуглишь, копаешься на стаковерфлоу, страдаешь - минимум минут 10 и больше
Сейчас:
- Спрашиваешь GPT, получаешь ответ - менее минуты (остальные 9 пишешь об этом пост в канал)

______________________________
@Backend простым языком
👍5😁4
Отложенный выстрел в ногу в SQL

Нашел в коде примерно следующий запрос:

SELECT books.id,
img_url,
name
FROM books
JOIN
authors ON books.author_id = authors.id;

То есть получаем айдишники книги, их картинки и имена авторов, которые хранятся в другой таблице. Запрос рабочий, вроде нет проблем, да? До поры до времени.

Сегодня он рабочий, потому что колонка img_url есть только в таблице books, а колонка name только в таблице authors. А вот айдишник есть в обеих таблицах, поэтому мы были вынуждены прописать явно из какой таблицы его брать.

Завтра (или через год) коллеге прилетает задача, что у авторов тоже есть лицо и мы хотим сохранять в таблицу их картинки. Он смело идет и первым делом добавляет в таблицу authors колонку img_url, а далее раскатывает на прод, ведь что можем быть безобиднее, чем просто добавить никого не трогающую новую колонку.

Но не тут то было. В другом конце кода лежит заряженный SQL запрос, который только и ждет, когда спустят курок. С добавлением в таблицу authors колонки img_url, наш запрос выше сломается, так как теперь неясно, какая именно колонка img_url в нем подразумевается. По итогу запрос будет выдавать ошибку ERROR: column reference “img_url” is ambiguous

Мораль: если вы в запросе джойните таблицы, всегда в селекте указывайте, откуда брать каждую из колонок

Запрос на предохранителе👇

SELECT b.id,
b.img_url,
a.name
FROM books b
JOIN
authors a ON b = a;

______________________________
@Backend простым языком
👍12
This media is not supported in your browser
VIEW IN TELEGRAM
Tab-chaos.

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

Все очень просто: ограничьте в редакторе количество активных вкладок до одной. Как говорил Брайан Трейси: “Я обещаю, это изменит вашу жизнь”. Больше не придется постоянно контролировать этот таб-хаус, клацать “Close other tabs”, искать среди тысячи открытых ту самую. Одна активная вкладка в один момент времени. Все.

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

______________________________
@Backend простым языком
👍7
Делюсь с вами крайне полезным инструментом, который судя по всему далеко не нов, но умудрялся обходить меня стороной. PlantUML - (грубо говоря) язык разметки, который позволяет текстом описывать разные диаграммы (sequence, activity, etc.) и генерить их представление с помощью плагинов. Особенно незаменимая вещь в крупных компаниях, где ценится документирование своей работы и в целом подобные артефакты.

Как начать пользоваться:
- Кидаете кусок кода в chatGPT с запросом generate me plantUML sequence diagram for code below
- Сохраняете результат к себе в проект и редактируете под нужды
- Profit

На сайте есть хорошая документация с множеством примеров, советую ознакомиться.

______________________________
@Backend простым языком
👍11
Какой язык программирования выбрать бэкендеру или почему я советую golang? Часть 1.

Осторожно: Статья супер субъективная. Когда ты пишешь на каком-то языке, создается ощущение, что весь мир крутится вокруг него, а остальные языки умирают (кроме php, там мир тебе напомнит, как обстоят дела), поэтому объективным быть в данном вопросе тяжело.

Теперь по поводу Golang. Предлагаю определиться с основными требованиями при выборе языка программирования. На мой взгляд от языка ожидается, чтобы:
1. Он приносил деньги - количество вакансий, уровень зарплат
2. Его относительно легко можно было освоить - обучающие материалы, курсы, отсутствие исторической нагроможденности языка ненужными возможностями
3. Был современным - тут тоже можно смотреть на вакансии, отсутствие жестких ограничений, использование крупными компаниями

______________________________
@Backend простым языком
👍4🤩1
Какой язык программирования выбрать бэкендеру или почему я советую golang? Часть 2.

Golang как по мне отлично подходит по всем пунктам:
1. С деньгами проблем нет, за него платят как минимум не меньше, чем за конкрутентов. Количество вакансий по ощущениями только растет.
2. Язык изначально заточен под легкость освоения, эта цель стояла у истоков его создания. Он сильно ограничен по количеству ключевых слов, притом не в ущерб возможностям. Есть проблема, что в русскоязычном пространстве ты не найдешь тонны курсов на любой вкус, но это может быть и плюсом.
3. Go создан в 2009ом году, то есть является довольно молодым, притом прогрессивно развивающимся языком, за которым стоит IT гигант Google. В пользу его современности и в целом главным аргументом для меня является то, что крупные компании переходят на него с других языков. Я думаю не нужно быть техническим директором, чтобы понимать: если крупная компания принимает решение о выборе нового основного языка, это должно быть чем-то крайне обоснованным и перспективным, так как сулит большие затраты и риски. Список компаний, ныне использующих Golang можете найти в поисковике, но вот короткий список известных мне компаний, перешедших на него:
- Авито - с PHP на Golang
- Wildberries - с C# на Golang
- Goods (ныне МегаМаркет) - c Nodejs на Golang

Решать в конечном счете вам самим. Главное помнить, что язык это только инструмент, его можно сменить в любой момент, и не стоит думать, что это выбор на всю жизнь.
______________________________
@Backend простым языком
👍10🤔2🤩2
Forwarded from archakov_blog
Сегодня Израиль (оккупированная территория Палестины) проводит невиданный миру за последние 50 лет геноцид палестницев, и весь "современный" мир закрывает на это глаза! 🇵🇸

Израильские террористы наносят авиаудары по больницам, где находятся больные дети, женщины, старики и через час заявляют, что это сделали сами палестинцы!

Людям навязывается диктат покинуть свои дома и в то же время наносятся авиаудары по мирной колонне!

Израильтяне оставили сегодня палестинцев без воды, света, интернета [1] [2] и медикаментов! При этом люди оказались в полной изоляции, без возможности бежать в соседние страны.

Я понимаю, что это канал про IT и как вы могли заметить, я никогда ранее не затрагивал политические темы, но речь сейчас идёт не о политике, а о преступлении против человечества. И хотите отписывайтесь от меня, хотите нет, но не поделиться этим я не могу!

(на фото так называемые "террористы", слабонервным не смотреть ⚠️)
👍201
О мусульмане, дуа за нашу Гaззy, дуа за мусульман! О Аллaх, пусть зeмля прoвалится под нoгaми этиx прoклятыx яхудов! Амин

📢📢📢
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23
Короткий совет вместо длинного поста:

Создавайте элиасы на айдишники в golang. Как минимум вам самим же легче будет разобраться, где какой айдишник используется и что же это за ключ int64 в мапе.

Еще пример, когда это избавит от потенциальных багов. Имеем функцию

func getLesson(userId int64, lessonId int64) (Lesson, error)

При ее вызове легко ошибиться и перепутать местами аргументы. Компилятор на такое не пожалуется, так как оба типа аргументов одинаковые.

Как можно было сделать лучше? Использовать элиасы:

func getLesson(userId UserId, lessonId LessonId) (Lesson, error)

При такой декларации перепутать аргументы уже куда сложнее 🙂

______________________________
@Backend простым языком
👍6
Яхья Картоев | Backend простым языком
Короткий совет вместо длинного поста: Создавайте элиасы на айдишники в golang. Как минимум вам самим же легче будет разобраться, где какой айдишник используется и что же это за ключ int64 в мапе. Еще пример, когда это избавит от потенциальных багов. Имеем…
Уточнение по предыдущему посту.

То, о чем я писал, называется Type Definition.

В go 1.19 же оказывается появились Type Alias. При инициализации они отличаются только знаком равно: type UserId = int64. Если рассматривать проблемы, описанные ранее, Type Alias решают только первую - повышение прозрачности кода. Но перепутать аргументы с ними по-прежнему легко, что делает их куда более узко применимыми. Подробнее о различиях тут.

Теперь непонятно, как по-русски называть Type Definition, элиасом уже как-то не назовешь. Кастомный тип? Ваши варианты?

______________________________
@Backend простым языком
👍4
Объявляем duration правильно

Плохо:

const someDuration = 720 * time.Hour // 1 month duration

Хорошо:

const someDuration = 30 * 24 * time.Hour // 1 month duration

В первом случае хоть и стоит комментарий, но:
- на него сходу не падает глаз и ты первые доли секунды не понимаешь, что значит магическое число 720
- если нужно будет сократить количество дней, например до недели, придется считать количество часов в неделе

Во втором случае:
- когда видишь 24 * time.Hour сходу понимаешь, что речь о дне (странно, что нет time.Day), а дальше уже понимаешь, сколько дней. Комментарий дополняет на случай особой непонятливости
- если нужно изменить количество дней - просто меняешь первую цифру на необходимую
👍6🤩4
Безопасное разыменование

Нередко бывает необходимость получить значение по указателю, либо если указателя нет, дефолтное значение типа. Например у тебя в структуре поле типа *string и тебе нужно переложить его в поле другой структуры с типом string

Раньше:

var userAddress string

if user.Address != nil {
userAddress = *user.Address
}

return userDto{
address: userAddress
}


С появлением дженериков это можно спрятать в функцию где-нибудь в /pkg


return userDto{
address: Safeder(user.Address)
}

// Safederef safety dereferencing pointer
func Safederef[T any](v *T) T {
var result T
if v != nil {
result = *v
}
return result
}
👍7
Наставление джуну, получившему свой первый оффер

Сегодня мой близкий знакомый по милости Аллаха получил свой первый оффер на роль джуниор бэкендера, вдобавок оффер оказался ощутимо выше ожидаемого. Это заставило меня запереживать, что успех может вскружить молодую голову и будут допущены неприятные ошибки. В связи с чем захотелось поделиться с ним (а заодно и с вами) парой советов по нескольким направлениям.

🕌 Религия.

Хороший оффер не может не радовать, особенно когда приложил для него множество усилий. Но не забывай про тех, кто приложил усилий больше, чем ты, но в итоге получил меньше. Результат приходит от Аллаха, не стоит приписывать его себе и восхищаться собой. Для тебя это большая ответственность, не забывай многократно благодарить Аллаха за такую возможность хорошо зарабатывать и распределяй деньги правильно. И пусть работа не отвлечет тебя от поклонения.

💻 Работа.

Бойся АллахIа в отношении своей работы. Это подразумевает ответственное отношение к своим трудовым обязанностям. Тебя может не видеть руководитель, но обязательно видит АллахI. Никогда не обманывай, ложь обречена на погибель. В случае проблем, лучше объясни, что пошло не так и какие уроки ты из этого вынес, а так же как планируешь исправлять. Старайся облегчить работу руководителю, он один, а вас много.

🤝 Коллеги.

Выстраивай открытые и искренние взаимоотношения с коллегами, это 80 процентов успеха на работе. Если тебе что-то не нравится в коллеге, выясни это 1 на 1, обосновав свою точку зрения, вежливо проясни вопрос. Никогда не обсуждай коллег за спиной. Пусть при твоем увольнении из каждой компании всей команде будет грустно от потери такого ценного и приятного коллеги.

💸 Зарплата.

Постарайся максимально не озвучивать сумму своего заработка людям. Это непросто, потому что нередко будут спрашивать напрямую, но можно вежливо уклоняться. Зарплата это не большой секрет, но людям эта информация не принесет ничего благого, максимум будет порождать вопрос "куда он столько тратит?!". Если кому-то необходимо знать, сколько зарабатывают айтишники, можно отправить его на статистику, это даст куда более объективную оценку рынка.

На этом остановлюсь, получилось и без того не мало. Надеюсь эти советы помогут в карьере и в жизни. И вся хвала принадлежит только Аллаху.
👍38🆒1
Экспериментальные пакеты

🧪 В go новые пакеты, прежде чем они будут добавлены в язык, попадают в специальный репозиторий экспериментальных пакетов golang.org/x/exp. Как сказано в описаннии данного репозитория, пакеты в нем в один прекрасный день могут попасть в язык как есть, могут попасть в измененном виде, а могут и вовсе не попасть.

Как-то раз мне нужна была функция для получения значений мапы в виде слайса. Поначалу реализовав ее вручную, я наткнулся на экспериментальный в то время пакет maps. Не желая тянуть в проект пакет, который как заявлено в любом момент может быть удален, я скопировал эталонную реализацию необходимой функции Values и положил ее к себе в проект, пометив комментарием: удалить эту функцию и использовать стандартную maps.Values после релиза go 1.21.

На днях мне опять понадобилась такая функция. Вспомнив свой коммент, я решил заодно поправить и там, ведь уже 1.22 вышел, какой там 1.21. Однако к большому удивлению, когда я полез в уже не экспериментальный, а офицальный пакет maps, необходимой функции Values там не оказалось😶 Она была исключена из пакета.

Такие вот эксперименты, с которыми нужно быть аккуратнеее. Коммент к Values я удалю, а реализацию оставлю и поделюсь с вами. Держите неудавшийся эксперимент:


func Values[M ~map[K]V, K comparable, V any](m M) []V {
r := make([]V, 0, len(m))
for _, v := range m {
r = append(r, v)
}
return r
}
👍5