Получи случайную криптовалюту за регистрацию!

dev notes

Логотип телеграм канала @junsenior — dev notes D
Логотип телеграм канала @junsenior — dev notes
Адрес канала: @junsenior
Категории: Технологии
Язык: Русский
Количество подписчиков: 1.63K
Описание канала:

Для связи @itxor
Twitter: https://twitter.com/SeniorJun

Рейтинги и Отзывы

4.33

3 отзыва

Оценить канал junsenior и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

2

4 звезд

0

3 звезд

1

2 звезд

0

1 звезд

0


Последние сообщения 4

2022-01-18 03:16:38 Начал покрывать тестами один старый проект на Symfony. В процессе настройки тестовой базы выяснилось, что часть миграций удалена, и создать схему только лишь миграциями - невозможно. Соответственно, использовать фикстуры в их стандартном флоу (пересоздал схему, накатил фикстуры) - тоже невозможно, а использовать их очень хочется.
В процессе поиска решения и разбора документации открыл два малоизвестных, но отличных бандла:
https://github.com/liip/LiipTestFixturesBundle и https://github.com/dmaicher/doctrine-test-bundle
Первый позволяет накатить фикстуры внутри теста, а второй автоматически оборачивает все запросы к базе в транзакцию, и после завершения теста откатывает её, оставляя базу в первозданном виде. Тем самым освобождая разработчика от необходимости пересоздавать схему. Огонь!
737 views00:16
Открыть/Комментировать
2022-01-17 11:47:00 ​Коротко о том, почему no-code/low-code системы ещё долго не смогут заменить обычную разработку
299 views08:47
Открыть/Комментировать
2022-01-17 07:55:09
380 views04:55
Открыть/Комментировать
2022-01-17 07:54:58 10-ая глава "Golang для профи" - продолжение темы асинхронщины, но уже более сложной. Постарался простым языком законспектировать основные тезисы подраздела о работе планировщика, велкоме.

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

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

Вторая - стратегия перехвата работы, спешит на помощь первой. Находим недостаточно загруженный процессор, и начинаем кидать на него все доступные задачи, пока ему не станет плохо. Когда всем процессорам плохо в равной мере - стратегия считает, что она выполнена успешно. Доступные задачи, которые можно кинуть на процессор - могут быть забраны у других процессоров, даже если они ранее на них уже начали выполняться. Если ты ничего не понял, но тебе очень интересно, этот момент круто объяснялся в курсе по Go на stepik от mail.ru. Рекламить не буду, кому нужно - сам найдёт :)

В go есть ещё одна интересная штука с непонятным названием: алгоритм планирования m:n. Внесём ясность: m - количество горутин, которые можно выполнить одновременно, а n - количество потоков (про потоки, процессы и горутины было в предыдущем конспекте, если не читал - рекомендую: https://t.me/junsenior/224). Этот алгоритм подразумевает, что есть глобальная очередь горутин: создали горутину, она улетела в очередь, а затем процессоры начинают определять, кто будет с ней работать.
Помимо глобальной очереди, доступной всем процессорам, есть ещё локальные очереди внутри каждого логического процессора. Из глобальной очереди горутины переезжают в локальные очереди, а затем начинают выполняться.

На картинке ниже P - логический процессор, М - поток операционной системы, а G - горутина. Это сжатое, но основное представление того, как устроен жизненный цикл работы горутин.
383 viewsedited  04:54
Открыть/Комментировать
2022-01-13 06:18:46 Начинаем день с 9-ой главы книги "Golang для профи" от Михалиса Цукалоса. Глава - весьма лёгкая, поэтому я записал либо общие термины, которые важно помнить, либо моменты, которые мне показались интересными.

Конкурентность и параллелизм - разные вещи. Параллелизм - возможность выполнить несколько задач параллельно, в один момент времени. Конкурентность - способ организации, при котором задачи выполняются тогда, когда это возможно. В случае go - когда одна задача уходит на ожидание, другая начинает выполнение. Если первая выходит из ожидания, пока вторая всё ещё выполняется - первая может продолжить выполняться в другом потоке.

Очень часто разработчики используют waitgroup для ожидания выполнения пачки горутин. Перед запуском горутины счетчик инкрементируется посредством waitgroup.Add(1), внутри горутины происходит декремент, посредством waitgroup.Done(), в основном потоке мы ждём завершения выполнения группы горутин с помощью waitgroup.Wait(). Если количество Add будет больше, чем Done - получим deadlock, если меньше - фатальное завершение, так что этот момент важно контролировать.

Канал - это механизм коммуникации, позволяющий обмениваться данными между горутинами. Канал создаётся с помощью make(chan type, bufferSize), где type - тип данных, проходящих через канал, а bufferSize - количество данных, которые канал сможет принять до блокировки. Канал можно закрыть с помощью метода close().
Если мы попытаемся считать данные из закрытого канала - мы получим нулевое значение соответствующего типа, а не ошибку. Это важный момент, часто являющийся поводом для ошибок, и который нужно обрабатывать.

Конвейер - паттерн, представляющий собой виртуальный метод, соединяющий горутины и каналы таким образом, что выходные данные одной горутины становятся входными данными для другой горутины.
Например:
var CLOSEA = false

var DATA = make(map[int]bool)

func random(min, max int) int {
return rand.Intn(max - min) + min
}
func first(min, max int, out chan <- int) {
for {
if CLOSEA {
close(out)
return
}
out <- random(min, max)
}
}
func second(out chan<- int, in <-chan int) {
for x := range in {
_, ok := DATA[x]
if ok {
CLOSEA = true
} else {
DATA[x] = true
out <- x
}
}
close(out)
}
func third(in <- chan int) {
var sum int
sum = 0
for x2 := range in {
sum = sum + x2
}
fmt.Println(sum)
}
func main() {
rand.Seed(time.Now().UnixNano())
A := make(chan int)
B := make(chan int)

go first()
go second()
third()
}

Похожим образом работает конвейер в unix: в консоли мы можем передать вывод одной программы на вход другой через вертикальный слеш: cat .env | grep psql

Далее автор приводит интересное сравнение моделей конкурентности в go и Rust:
* потоки Rust - это потоки UNIX, соответственно - они гораздо более тяжелые, чем горутины
* Rust поддерживает конкурентность на основе обмена сообщениями и на основе совместного использования состояний - то же самое, что в Go реализовано с помощью каналов, мьютексов и общих переменных
* строгая типизация и система владения позволяет Rust обеспечивать безопасное изменяемое состояние потока
* Rust позволяет, с помощью специальных структур, совместно использовать состояния потока
Резюмируя, у Rust есть гибкая модель конкурентности, ещё более гибкая, чем у go. Но, чтобы её использовать, приходится мириться с Rust :)

Далее - ещё одно сравнение, между Go и Erlang:
* в Erlang используется только асинхронная коммуникация
* в Erlang реализована система обработки ошибок, позволяющая создавать надёжные конкурентные системы
* сбои процессов во время конкурентной работы можно ловить и обрабатывать
* как и горутины, процессы в Erlang являются изолированными, у них нет общих состояний. Единственный способ взаимодействия между процессами - передача сообщений
* Потоки Erlang такие же лёгкие, как и горутины.
Система конкурентности в Erlang, в общих чертах, больше похожа на систему конкурентности в Go, так что если тебе нравится Erlang - можно смело его юзать :)
255 views03:18
Открыть/Комментировать
2022-01-12 07:31:54 В прошлом году я начал работать в vim и это было отличным решением.

Vim мне всегда казался чем-то трушным, с чём настоящий разработчик обязательно должен научиться работать. Но, вот ты берёшь шпаргалку по комбинациям, открываешь консоль, и пальцы начинают бегать по клавиатуре, на мониторе летят знаки словно в матрице.. нет, на самом деле ничерта не получается. Пальцы не слушаются, бегать по коду не получается. А как тут искать текст? А как заменить? Что произошло и почему все стало капсом? Я забыл, а как искать? Полчаса ты страдаешь, закрываешь vim и думаешь: "ну, когда-нибудь потом". Обычно, потом либо никогда не наступает, либо разработчик убеждает себя в том, что vim - это что-то древнее, и вообще зачем он, если есть IDE? В прошлом году я решил предпринять последнюю попытку к его освоению. Забегая вперёд - она увенчалась успехом.

Начал я с освоения 10ти пальцевой печати. Без неё в vim делать нечего, и это основная причина, почему многие не могут там работать. Нет, проблема не в твоих пальцах, проблема в том, что не все из них работают, а vim это подразумевает. Я пользовался https://www.ratatype.ru/ и мне хватило двух недель, чтобы пройти и курс на русском, и курс на английском, в перерывах между работой. Ещё через пару недель появилась привычная скорость.

Затем, настал черёд vim. В первый день я поставил его как плагин к IDE, открыл рабочий проект и несколько часов страдал, отрабатывая основные комбинации. Ещё через пару часов уже можно было бегать по коду, выделять слова и делать базовую работу. Через пару дней я уже сносно писал код, временами подглядывая в шпаргалку. Через неделю набралась достаточная скорость. С тех пор и по сей день всё, что я делаю - это временами смотрю новые комбинации и пытаюсь их добавить к уже освоенному набору. Как результат - сейчас писать код без vim уже не получается :)

Говорят, что один из главных плюсов vim - скорость. Пока у одного открывается IDE, vim-фанатик уже заканчивает разребать бэклог. Но, нет.
По началу я попробовал писать весь рабочий код в vim, но быстро ушёл от этой идеи. При большом желании vim почти не будет уступать IDE, но есть вещи, которые я в нём настроить не смог. Во-первых, это отладчик. Его удалось запустить и даже понять, как с ним работать. Но, я настолько часто им пользуюсь и настолько привык к его реализации от JetBrains (как в Goland, так и в PHPStorm), что vim'овская версия проигрывала в сухую. Во-вторых, через IDE я часто работаю с докером и базами. От этого тоже не хотелось отказываться, так что моё текущее решение - просто vim-плагин для IDE :)
В vim же я работаю только с небольшими проектами, и преимущественно на go, потому что vim с go, субъективно, работает лучше. Отладчик - сносный, автокомплит не уступает IDE, все другие возможности языка так же поддерживаются.

Настраивать vim можно бесконечно, играясь с сотнями плагинов, меняя комбинации и шорткаты, настраивая отладчики и кастомизируя внешний вид. Я использую neovim - форк vim, но с большими возможностями. Чтобы не делать из этой заметки чтиво на пару часов - просто приведу пример своего конфига: https://github.com/itxor/nvim-configs. Это стандартное решение, приводимое в большинстве статей, в которое я добавил несколько плагинов, делающих из nvim что-то более-менее похожее на IDE. Если ты дошёл до этапа кастомизации и у тебя появились какие-то вопросы - смело пиши в комменты, обсудим.
424 views04:31
Открыть/Комментировать
2022-01-07 21:39:10 С наступившим! Первым постом в новом году хочу обсудить что будет с этим каналом и куда мы будем двигаться.

Изначально я создавал этот канал как некий девлог на пути становления синьором, на который я себе выделил 1000 дней. Сейчас и 1000 дней уже прошли, и эта идея у меня вызывает улыбку, потому что синьор, в моём текущем понимании, это никак не 1000 дней разработки. :) Тем не менее, я хорошо продвинулся и много чего освоил за это время, и канал мне в этом помог.
Мне всегда нравилось чем-то делиться и что-то писать, и тем более получать от вас обратную связь. Но, рамки контента, которые я сам себе установил, не позволяли писать что-то, кроме статей по конретной теме или конспектов по чему-то прочитанному или понятому. Такой формат контента заставляет постоянно что-то учить (что, несомненно, плюс). Но, большие статьи и конспекты занимают много времени, делать часто их не получается, перерывы становятся всё больше и мотивация что-то писать пропадает (за прошлый год таких периодов было немало).
В этом году я решил это исправить и дать себе свободу писать сюда любые заметки и обсуждать с вами любые интересующие меня и вас вопросы, связанные с разработкой и миром вокруг неё. Я надеюсь, что и мне и вам такой формат понравится :)

Олды помнят, что как-то раз я проводил стрим, на котором писал бот для телеги на NodeJS (ох, как хорошо что его не осталось в записи :D). В этом году попробую возобновить стримы, но в формате лайв-кодинга, так как подготовиться к конкретной теме, опять же, занимает много времени, а просто писать код по моим текущим проектам - дополнительного времени, кроме как нажать на кнопку стрима, не займёт. Я, когда что-то пишу, частенько включаю лайв-кодинг себе фоном, надеюсь, что и кому-то из вас такой подход зайдёт.

В новом году желаю всем нам бустануть свои знания, не перерабатывать, заниматься любимым делом и сделать так, чтобы любимое дело совпало с работой :)
252 views18:39
Открыть/Комментировать
2021-12-09 09:16:25 Продолжаю конспекты "Golang для профи" Михалиса Цукалоса. Ниже конспект основных мыслей по нескольким темам из главы про структуры данных.

Пользовательские хеш-таблицы.
Хеш-таблица - стуктура данных, хранящая пары вида ключ-значение, где ключ определяется функцией, вычисляющей местоположение очередного добавляемого элемента.
Реализация, предложенная автором - https://github.com/PacktPublishing/Mastering-Go-Second-Edition/blob/master/ch05/hashTable.go
Одно из преимуществ хеш-таблиц - ключом может быть что угодно, в отличии от массива или слайса, где ключом может быть только положительное целое число.
Основное преимущество пользовательских хеш-таблиц - ассимптотика поиска: если хеш-таблица имеет n ключей и k блоков, то скорость поиска будет О(n/k), вместо обычной линейной О(n). Это кажется незначительным, но для массива хешей, состоящего из 20 блоков, время поиска сократится в 20 раз, что даёт очень хороший выигрыш для приложений-словарей и приложений, где нужно искать большие объёмы данных.

Реализацию пользовательского связного и двусвязного списка, очереди и стека я пропущу, и перейду сразу к интересному: стандартному go-пакету container, предоставляющему три стуктуры данных: кучу, список и кольцо. Для справки: кольцо - циклический список, где последний элемент ссылается на первый.

Пакет container/heap реализует кучу - дерево, где значение каждого узла является наименьшим элементом в его поддереве. Но, чтобы реализовать дерево кучи в go, необходимо определить операцию сравнения, чтобы понять, какой из двух элементов меньше (т.к. элементом может быть что угодно, не только числа). Для реализации такой возможности пакет container/heap предоставляет интерфейс container/heap.Interface, который опеределяется как:
type Interface struct {
sort.Interface
Push(x interface{})
Pop() interface{}
}
Для интерфейса sort.Interface, в свою очередь, требуется реализовать методы Len(), Less() и Swap().
И, кажется, это очень удобно: реализовав эти методы для наших структур или типов, мы получим возможность сортировать, менять местами и использовать элементы в рамках кучи.
Реализация, предложенная автором - https://github.com/PacktPublishing/Mastering-Go-Second-Edition/blob/master/ch05/conHeap.go
Пример показывает, что работы, которая требуется для реализации этого интерфейса, требуется проделать совсем немного.
250 viewsedited  06:16
Открыть/Комментировать
2021-12-06 05:10:32 Благодаря обзору от https://t.me/johenews приобрёл себе "Golang для профи" Михалиса Цукалоса. Вывод после первых 200 страниц: автор хорошо знает свой материал, делится огромным массивом знаний, и почти не льёт лишней воды, но структура книги и порядок изложения информации кажется немного сумбурным. С другой стороны, аудитория - явно знакомые с синтаксисом языка люди, имеющие какой-то опыт в разработке, которые и без плавных переходов должны понимать материал. Так что, учитывая полное отсутствие нормальной литературы по golang, книжка весьма и весьма хорошая.

А я, тем временем, начиная с 5-ой главы, решил начать вести краткие конспекты, как ранеее делал с "Высоконагруженными приложениями" Клеппмана, и "Микросервисами" Ричардсона. Так что, ловите первый конспект по главе "Как улучшить код Go с помощью структур данных".

Автор даёт интересное определение сложности алгоритма: сложность алгоритма определяется главным образом тем, сколько раз алгоритму для выполнения его работы требуется доступ к входным данным.
В go большинство операций, таких как поиск значения по ключу в хеш-таблице, или доступ к элементу массива, имеют постоянное время - О(1).
Не все структуры данных одинаковы: в go операции с массивами выполняются быстрее, чем операции с хеш-таблицами.
Первая рассматриваемая автором структура - двоичное дерево. Реализация - https://github.com/PacktPublishing/Mastering-Go-Second-Edition/blob/master/ch05/binTree.go
Если нам нужно представить иерархические данные - нет ничего лучше двоичного дерева. Если дерево сбалансировано, то операция поиска, вставки и удаления элементов выполняются за log(n), а высота дерева приблизительно равна log^2(n). Например, высота дерева из 100 000 элементов - 17, а из 1 000 000 - около 20. Т.е. мы можем достичь любой элемент дерева за менее чем 20 шагов, что очень круто.

Двоичное дерево следует использовать только если у дерева простые ключи, чтобы операции вставки и поиска не были слишком сложные, и если дерево возможно поддерживать в упорядоченном виде, чтобы не нарушать ассимптотику операций вставки, поиска и удаления. При этом важно понимать, что массив или список создаются и инициализируются быстрее, но скорость получения данных, предоставляемая двоичным деревом, порой может окупить потерю времени при инициализации.
294 viewsedited  02:10
Открыть/Комментировать
2021-12-03 08:02:43 https://twitter.com/usehex/status/1466455196754759684
412 views05:02
Открыть/Комментировать