• Нужно ли везде использовать TypeScript? или это хайп?

    Xuxicheta
    @Xuxicheta
    инженер
    Нужно ли везде использовать TypeScript?

    ну видимо нет.

    или это хайп?

    нет

    Есть ли смысл использовать Typescript в пет проектах?

    Писать на ts тупо удобнее, отлавливает сразу простые ошибки и предоставляет автодополнение и информацию о сигнатурах.

    типа создал мини игру 15 строчках кода на TypeScript?

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

    Или он только в крупных проектах нужен? и вообще все прям без него будто не могут писать судя по отзывам или это какойто хайп или реклама Microsoft

    еще раз. ts - удобнее и надежней.
    Ответ написан
    2 комментария
  • Почему Go с горутинами работает на одном ядре?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Горутины выполняются на разных процессорах как и должны, у вас четвёртое число слишком большое, все горутины завершают выполнение, а одна продолжает работать. По этому и создаётся впечатление, что они все работают на одном ядре.

    Чтобы в этом убедиться добавим два fmt.Printf, чтобы получилось вот так
    package main
    
    import (
        "fmt"
        "runtime"
        "sync"
    )
    
    var wg sync.WaitGroup
    
    func main() {
        runtime.GOMAXPROCS(8)
        arr := []int{1343434, 1343434300, 234343400, 334343434000, 400434340, 203434340, 4232, 23545, 15535, 353535, 33434434, 5334345, 3533434345, 3535}
        for idx, el := range arr {
            wg.Add(1)
            go test(el, idx)
        }
        wg.Wait()
    }
    
    func test(el int, idx int) {
        fmt.Printf("%d started: %d\n", idx, el)
        for i := 0; i < el; i++ {
            el = el - 1
        }
        fmt.Printf("%d completed: %d\n", idx, el)
        defer wg.Done()
    }


    Вывод будет примерно таким
    4 started: 400434340
    8 started: 15535
    8 completed: 7767
    13 started: 3535
    13 completed: 1767
    6 started: 4232
    6 completed: 2116
    10 started: 33434434
    3 started: 334343434000
    7 started: 23545
    7 completed: 11772
    5 started: 203434340
    12 started: 3533434345
    11 started: 5334345
    2 started: 234343400
    1 started: 1343434300
    11 completed: 2667172
    9 started: 353535
    9 completed: 176767
    0 started: 1343434
    0 completed: 671717
    10 completed: 16717217
    5 completed: 101717170
    4 completed: 200217170
    2 completed: 117171700
    1 completed: 671717150
    12 completed: 1766717172

    При внимательном просмотре станет видно, что нет записи 3 completed.

    меняю элементы с индексами 4 и 5 на такие же числа 334343434000, 334343434000, т.е. делаем чтобы все горутины отработали, но чтобы 3 осталось, т.е. вот так

    arr := []int{1343434, 1343434300, 234343400, 334343434000, 334343434000, 334343434000, 4232, 23545, 15535, 353535, 33434434, 5334345, 3533434345, 3535}


    Запускаем заново и видим, что теперь 3 ядра отлично загружены
    %Cpu0  :  0.3 us,  1.0 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu1  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu2  :  1.7 us,  0.7 sy,  0.0 ni, 97.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu3  :  1.6 us,  2.9 sy,  0.0 ni, 95.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu4  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu5  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu6  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu7  :  5.6 us,  1.0 sy,  0.0 ni, 93.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    Ответ написан
    Комментировать
  • Деобфусцировать js имеющий _0х?

    dollar
    @dollar
    Делай добро и бросай его в воду.
    Защита основана на том факте, что дешевле сделать своё собственное решение, чем вскрывать защиту. Так что выбор простой:
    1) Заплатить тому, кто написал оригинальный скрипт.
    2) Заплатить другому, кто может написать такой же скрипт.
    3) Чуть больше заплатить тому, кто снимет защиту.

    Лично я на твоём месте выбрал бы платить меньше, а не больше.
    Ответ написан
    Комментировать
  • В чем сложность поддержки проектов на 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 комментариев
  • Что выбрать для телеграм бота? Вебхуки или лонгполлинг?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    "Long polling" периодически опрашивает телеграм сервер, за счёт этого пользователю будет казаться, что бот "торзмозит", т.к. между отправкой сообщения от пользователя и до получения ответа будут паузы.
    По крайней мере у меня было именно так.
    Еще стоит сказать о том, что "Long polling" не подойдёт если говорить о нагрузках.

    После перехода на WebHook'и - сразу заработало всё очень резво.
    Также с использованием WebHook'ов у вас будет возможность горизонтально масштабировать бота в случае роста нагрузок.
    Если бы у меня стояла такая задача - я бы использовал WebHook'и.
    Ответ написан
    3 комментария
  • Как в gorilla mux сделать серверную мидлвару?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Есть вариант использовать httptest.ResponseRecorder, я его использовал ранее для написания тестов.

    https://pkg.go.dev/net/http/httptest#ResponseRecorder

    Пример будет примерно таким
    func (m *LoggingMiddleware) LogBody(next http.Handler) http.Handler {
        fn := func(w http.ResponseWriter, r *http.Request) {
            wRecorder := httptest.NewRecorder()
            next.ServeHTTP(wRecorder, r)
            resp := wRecorder.Result()
            body, _ := io.ReadAll(resp.Body)
            // не забыть записать ответ в w
        }
    
        return http.HandlerFunc(fn)
    }


    Пример его использования из официальной документации https://pkg.go.dev/net/http/httptest#example-Respo...

    Или, можно сделать свой responseWriter, в handler передавать свой writer, а потом, после обработки, записать полученный ответ сервера в оригинальный responseWriter
    Что-то типа такого
    func (m *LoggingMiddleware) LogBody(next http.Handler) http.Handler {
        fn := func(w http.ResponseWriter, r *http.Request) {
            var buf bytes.Buffer
            logWriter := NewLogToConsoleResponseWriter(&b)
            next.ServeHTTP(logWriter, r)
            // тут у вас в buf будет ответ сервера, с которым можно работать
            // главное потом не забыть записать его в `w`
        }
    
        return http.HandlerFunc(fn)
    }
    Ответ написан
    5 комментариев
  • Как распарсить массивы из yaml в golang?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    У вас поля в структуре не экспортируемые, по этому и не работает.
    Вот рабочий пример
    package main
    
    import (
        "fmt"
        "io/ioutil"
    
        "gopkg.in/yaml.v3"
    )
    
    func main() {
    
        fmt.Println("start")
    
        c, err := readYaml("./tets.yml")
    
        if err != nil {
            panic(err.Error())
        }
    
        fmt.Println(c.Master, c.Kibana, c.Data, c.Pass, c.User)
    }
    
    type ClusterEnv struct {
        Master []string `yaml:"master,flow"`
        Data   []string `yaml:"data,flow"`
        Kibana []string `yaml:"kibana,flow"`
        User   string   `yaml:"user"`
        Pass   string   `yaml:"pass"`
    }
    
    func readYaml(filename string) (*ClusterEnv, error) {
    
        buf, err := ioutil.ReadFile(filename)
        if err != nil {
            return nil, err
        }
    
        c := &ClusterEnv{}
        err = yaml.Unmarshal(buf, c)
        if err != nil {
            return nil, fmt.Errorf("in file %q: %v", filename, err)
        }
    
        return c, nil
    }
    Ответ написан
    Комментировать
  • Нужен ли Nginx для веб приложения на Golang?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Не нужен, в Go есть полноценный веб сервер.

    Nginx есть смысл использовать в случае если есть необходимость обслуживать больше одного домена на одном и том же IP:Port, ну и для раздачи статики (изображений, CSS, Javascript и т.д.)

    Еще есть смысл использовать Nginx когда у вас большая нагрузка и ваш сервис на Go работает на нескольких серверах - Nginx'ом можно балансировать нагрузку между этими серверами.
    Ответ написан
    9 комментариев
  • Мы можем работать с map так же, как с массивом?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Map ничего общего не имеют с массивами, они реализуют совершенно другую структуру данных - хэш таблицу

    От объектов так же есть отличия:
    - У объектов в качестве ключа может быть только строка или символ, у Map - любой тип
    - Map под капотом всегда представлены как OrderedHashMap (упорядоченная хэш таблица), объекты представлены той же структурой данных, но в отличии от Map после оптимизации могут быть представлены в виде обычных сишных структур, где нужное поле получается по смещению от указателя.
    - Для манипуляции с объектами есть множество синтаксического сахара (вроде оператора in или spread (...) оператора), и оптимизатор знает об этом сахаре. У Map есть только его методы, с которыми оптимизатор может сделать не так уж и много (так как некоторые оптимизации не применимы к динамическому диспатчингу, ибо ведут к UB, а JS - язык с гарантированным отсутствием UB)
    Ответ написан
    2 комментария
  • Как понять когда ставить указатель?

    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 (а это её значение)


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

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

    gbg
    @gbg
    Любые ответы на любые вопросы
    Не можно. И это хорошо.
    Ответ написан
    Комментировать
  • Может-ли быть пустой JS на 1 Гб?

    @kirillinyakin
    Наврядли там пустота, так как скорее всего файл не успевает выгружаться в оперативку. А так есть несколько вариантов:
    1) Неправильное расширенин файла
    2) Кто то создал пустой блоб файл и поставил ему расширение джса по приколу
    Ответ написан
    Комментировать
  • Как назначать класс активному элементу внутри блока независимо от других блоков?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где элементы находятся, что за элементы, какой класс у них надо переключать:

    const containerSelector = '.block-btn';
    const itemSelector = `${containerSelector} [data-cost]`;
    const activeClass = 'active';

    Какие тут возможны варианты:

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

    const onClick = ({ currentTarget: t }) => t
      .closest(containerSelector)
      .querySelectorAll(itemSelector)
      .forEach(n => n.classList.toggle(activeClass, n === t));
    
    document.querySelectorAll(itemSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });

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

    for (const n of document.querySelectorAll(containerSelector)) {
      n.addEventListener('click', onClick);
    }
    
    function onClick(e) {
      const item = e.target.closest(itemSelector);
      if (item) {
        this.querySelector(`.${activeClass}`)?.classList.remove(activeClass);
        item.classList.add(activeClass);
      }
    }

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

    document.addEventListener('click', ({ target: t }) => t
      .closest(itemSelector)
      ?.closest(containerSelector)
      .querySelectorAll(itemSelector)
      .forEach(n => n.classList.toggle(activeClass, n.contains(t)))
    );
    Ответ написан
    2 комментария
  • Как распарсить время для понимания JS?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const date = new Date(str.replace(/\S+/, m => m.split('.').reverse().join('-')));

    или

    const date = new Date(str.replace(/(\d+)\.(\d+)\.(\d+)/, '$3-$2-$1'));

    или

    const [ day, month, year, hours, minutes, seconds ] = str.split(/\D/);
    const date = new Date(year, month - 1, day, hours, minutes, seconds);

    или (day.js):

    const date = dayjs(str, 'DD.MM.YYYY HH:mm:ss').toDate();
    Ответ написан
    Комментировать
  • Как удалить 0 в начале числа?

    nedosekinstanislav
    @nedosekinstanislav
    Штирлиц как никогда был близок к провалу
    parseInt()
    но он принимает строку, можно преобразовать полученное значение String(value)
    Ответ написан
    Комментировать
  • В чем преимущество функций-конструкторов?

    @antares4045
    Разница в механике наследования: первый вариант можно унаследовать, и ему в прототип можно добавлять методы.

    в первом случае, если вы захотите добавить метод, который выводит имя в консоль, то вам будет достаточно
    написать
    Func.prototype.printName = function(){
      console.log(this.name)
    }


    и затем можете обращаться к методу
    a.printName() // выведет в консоль Victoria
    При всём при том, не зависимо от того, сколько экземпляров класса Func вы наплодите метод printName в памяти будет храниться один.

    Во втором случае вы также при помощи несложных манипуляций сможете добиться похожего поведения, но там всегда будут подводные камни, например скорее всего у вас не получится создать наследника для func
    Ответ написан
    Комментировать
  • Как проверить строку, есть ли в начале определенные символы?

    udjin123
    @udjin123
    PHP, Golang, React
    strings.HasPrefix("Gopher", "Go")

    Документация тут
    Ответ написан
    Комментировать
  • Как заставить функцию ждать выполнения события click?

    0xD34F
    @0xD34F Куратор тега JavaScript
    async function Func() {
      console.log('START');
    
      await new Promise(r => {
        $('div').one('click', () => (console.log('CLICK'), r()));
      });
    
      console.log('END');
    }
    Ответ написан
    Комментировать