Занимаюсь коммерческой разработкой 22 года.

Имею пять международных сертификатов.

Первый интернет магазин разработал в 1998 году.

5 лет работал удалённо в компаниях США.

Разрабатывал:
- CMS, CRM, ERP системы (системы управления контентом, клиентами, предприятиями);
- интернет магазины;
- высоконагруженные сервисы;
- индексаторы сайтов;
- балансировщики нагрузки, сервисы очередей;
- систему слежения за автомобилями;
- панели управления серверами;
- ПО для медицинского оборудования;
- ПО для управления линиями по производству композитной арматуры;
- и многое другое.

С радостью поделюсь накопленным опытом и знаниями.

Контакты:
Skype: evgeny.mamonov
WhatsApp, Viber: +79885762574
Telegram: EvgenyMamonov
Местоположение
Россия, Краснодарский край, Горячий Ключ

Достижения

Все достижения (9)

Наибольший вклад в теги

Все теги (59)

Лучшие ответы пользователя

Все ответы (157)
  • В чем сложность поддержки проектов на Go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Более четырёх лет пишу на Go, лично для меня поддерживать проекты на других языках сложнее ))
    До Go много лет писал на Perl/PHP/Python/Java/C/Ruby on rails/JavaScript и "крутил" еще не мало чего.
    Сейчас пишу только на Go и Python.

    Основная сложность в Go - это то, что если вы начинаете писать "криво" - то писать так очень трудно :))
    Подход к реализации в Go достаточно непривычный для тех, кто приходит из скриптовых языков.
    Например запрет циклических импортов - это самое первое, что "взрывает" мозг :)
    Нужно время чтобы адаптироваться после скриптовых языков.

    Про обработку ошибок - это да, это, пожалуй, единственное что мне не нравится в Go.
    Для себя я решил эту проблему за 1-2 часа :) и больше меня это не беспокоит.

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

    А если объективно - то я бы не стал говорить о сложности поддержки проекта применимо к какому то конкретному языку.

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

    А когда в таком проекте нужно что-то доработать или исправить ошибку, то почти всегда очень не просто найти то место, где нужно править, и после правок в одном месте, как правило, что-то ломается в другом :)

    Как минимум, нужно соблюдать принципы SOLID, иначе код получается, мягко говоря, не поддерживаемым.
    Но понимание этих принципов так же приходит с опытом, их нельзя научиться соблюдать просто прочитавши книгу или статью. Нужно сделать несколько проектов используя эти принципы, написать криво, понять как было бы правильно, всё переделать и так несколько раз.
    Тогда, со временем, начнёт получаться понятный и легко поддерживаемый код.

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

    Хочется добавить, что как бы не писали про Go, что он простой и т.д. - он явно сложнее Python/PHP и т.д.
    Это еще один повод сказать, что поддерживать код на Go сложно ))

    Также стоит учитывать, что проекты которые пишут на Go зачастую сложнее, чем проекты для которых выберут скриптовый язык. Go выбирают когда планируются большие нагрузки, параллельная обработка чего-либо и т.д., а это, в свою очередь, дополнительно усложняет проект.
    Ответ написан
    7 комментариев
  • В каких приложениях Go существенно эффективнее чем Node.js и PHP?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Бенчмарки - это хорошо, но очень важно понимать что именно там меряли и почему результаты именно такие.

    Несколько лет назад я тоже делал бенчмарки Python, PHP, Node, Go.
    Для меня были важны две вещи:
    1 - скорость ответа сервера/кол-во запросов в секунду
    2 - объём сервиса в памяти, т.к. от этого зависит стоимость ресурсов

    На тесте, где сервисы не делали запросы в базу - из всех четверых лучше всего отработал Go с приличным отрывом, цифры, к сожалению, уже не помню.

    Но вся эта разница сошла на нет, как только добавился всего один простой SQL запрос в базу, в таблицу с 10 строками. И на этом фоне разница по скорости ответа была меньше 10%.

    Иными словами если ваш сервис работает с базой - критической разницы по скорости работы между Go/Rust/PHP/Node/Java, особо не будет.

    Другое дело если ваш сервис не будет делать запросы в базу, или будет кешировать результаты запросов, тогда вы почувствуете ощутимую разницу.

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

    Один экземпляр Go занимал в памяти порядка 6мб RAM, при том, что Pytho+Django порядка 60мб.
    Node уже не помню сколько, но что-то близкое к Python'у.

    Вот тут уже, когда серверов у вас будет много - количество серверов с Go у вас будет в 10 раз меньше, соответственно расходы за эти сервера у вас будут в 10 раз меньше :)

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

    Где-то читал статью, что у людей было API на порядка 40 серверов на Node, после переписывания на Go - серверов осталось два, из которых второй запасной :)
    Ответ написан
    14 комментариев
  • Как понять когда ставить указатель?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Указатель, по сути, хранит адрес каких то данных (переменной, структуры, слайса и т.д.).
    Иными словами он "указывает" на область данных.

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

    Например:
    type BigStruct struct {
        field1 int
        filed2 string
        field3 uint
        field4 []byte
        ...
        field50 string
    }

    Предположим, что после создания этой структуры и заполнения всех её полей она занимает в памяти 300мб.

    Если вы сделаете функцию, которая будет принимать такую структуру как агрумент, например вот так
    func Report(s BigStruct)
    то при каждом вызове этой функции вся структура (300мб) каждый раз будут копироваться.
    Пример:
    s := BigStruct{}
    // заполняем поля
    Report(s)


    Чтобы избежать такой мега нагрузки - можно передавать не копию данных, а указатель, т.е. адрес в памяти, где хранится сама структура.
    Для этого нужно объявить агрумент функции как указатель, т.е. ставим *.
    func Report(s *BigStruct)
    А код уже будет выглядеть вот так.
    s := BigStruct{}
    // заполняем поля
    Report(&s) // тут добавился & - берём адрес структуры, а не саму структуру

    Или второй вариант
    // создаём переменную s сразу с типом указатель на BigStruct
    s := &BigStruct{}
    // заполняем поля
    Report(s) // поскольку s уже является указателем - & тут не нужен


    В общем * используется:
    - когда нужно объявить переменную
    var s *BigStruct
    - когда нужно прочитать/записать значение, которое храниться по адресу указателя
    var i *int
        i = new(int)
        *i = 10 // пишем значение
    
        fmt.Printf("i: %v\n", i)
        fmt.Printf("*i: %v\n", *i)

    Вывод будет примерно таким
    i: 0xc0000160d8 (это адрес памяти, где лежит значение переменной i)
    *i: 10 (а это её значение)


    & (амперсанд) используется когда нужно получить адрес переменный.

    Еще один вариант применения - если нужно иметь возможность модифицировать данные у параметра функции. Если нужны примеры - дайте знать, я напишу.
    Ответ написан
    13 комментариев
  • Структура проекта на Golang?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Добрый день.

    Это попытка стандартизировать структуру проекта (многие ориентируются на неё)
    https://github.com/golang-standards/project-layout

    Go-Kit - очень грамотная структура, очень
    https://github.com/go-kit/kit

    И обязательно стоит посмотреть
    https://12factor.net/ru/

    Что касается "Т.е. в одном файле может быть сразу модель, сервис и репозиторий. Есть ли какие-то бестпркатики по этому вопросу?" - то это не совсем так, в одном пакете (папке) может быть и модель, и сервис, и репозиторий". Например вот так:
    yourpackage/service.go
    yourpackage/repo.go
    yourpackage/model.go
    И это всё будет доступно в рамках пакета.

    Лично я использую такую схему:
    cmd/ - команды исполняемого файла
    conf/ - конфиги приложения (env файлы)
    init/ - конфиги logrotated, nginx, systemd и т.д.
    pkg/ - публичные пакеты
    pkg/packagename/ - тут определяются интерфейсы (сервиса, репозитория и т.д.) в разных файлах
    pkg/packagename/endpoints/http - endpoint'ы для HTTP
    pkg/packagename/repo/mysql - реализация репозитория на MySQL
    pkg/packagename/repo/gorm - реализация репозитория на GORM (для примера)
    pkg/packagename/service/ реализация сервиса

    Я написал очень кратко, если что-то не понятно или есть вопросы - пишите, я опишу подробнее
    Ответ написан
    Комментировать
  • В каких случаях возвращать указатель при создании структуры?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Это можно определить по таким параметрам:
    - размер структуры
    - частота "пробрасывания" этой структуры в другие функции.
    - необходимостью модификации структуры внутри функции

    Размер структуры
    Если размер структуры маленький, и её после её формирования вы передадите её в 1-2 функции - лучше возвращать структуру, т.к. при копировании структуры не будет накладных расходов на сборку мусора
    Если размер структуры большой, то лучше использовать указатель, т.к. при передаче его как параметр в другие функции копироваться будет 8байт (для 64битных систем), а не вся структура. За счёт этого будет большой выигрыш в производительности, но будут накладные расходы на сборку мусора.

    Частота "пробрасывания" стркутуры в другие функции.
    Если структура не большая, но потом она будет передаваться в много разных функций - накладные расходы в этом случае будут больше, чем при передаче просто указателя, в этом случае лучше использовать указатель.
    Пример:
    s := SomeStruct{..}
    func1(s)
    func2(s)
    ...
    func10(s)

    В данном случае структура будет 10 раз скопирована через стэк, по одной копии на каждый вызов функции.
    А если передавать как указатель - тогда каждый раз будет копироваться всего 8 байт.

    Необходимость модификации структуры внутри функции
    Если вам нужно внести изменения в структуру и при этом не возвращать её из функции - это не сделать, если не использовать указатель, т.к. в этом случае функция получит копию структуры.
    Пример:
    type User struct {
        Name string
        Password []byte
    }
    func SetPassword(u *User) {
        u.Password = []byte(...)
    }
    // или
    func (u *User) GeneratePassword() {
        u.Password = []byte(...)
    }

    Если тут не использовать указатель - изменения в оригинальной структуре не произойдут, т.к. фунция будет менять копию структуры.
    Ответ написан
    4 комментария