• Каковы зарплаты junior frontend разработчика?

    @Stergy
    Как по мне все довольно индивидуально, у меня опыт 1 год и 3 месяца.
    Начинал практически с нуля.
    Мои зарплаты по месяцам если интересно.
    1й-3й месяц работы 10к рублей в месяц - знания нулевые, в основном учил основы
    после 3 месяцев сменил работу, ибо устали меня учить и получалось так себе, решил уйти + это была удаленка, прибавляй все сопутсвтующие сложности
    3й месяц - 1 год работы устроился в офис стажером, зп $200 - $800 (варировалась т.к. была почасовка и зп менялось в зависиомости от отработанных часов)
    После года - новая работа, работаю с июля(уже 3 месяца) Зп в районе $2000.
    Опять же уровень свой оцениваю - как низкий, серьезный буст по зарплате в моей ситуации происходит только при смене работы. В рамках одной работы больше чем на 1,5$ в час за раз не повышали.
    Вот как-то так, отвечая на ваш вопрос, что сейчас что год назад я джун. Но за год я вырос значительно, но весь рост все равно в рамках джуна. Поэтому нужно учитывать какого джуна ищут и что хотят видеть. Вряд ли абсолютному новичку дадут сразу 80к рублей, думаю для этого все же нужно немного повариться за меньшую зп.
    Ответ написан
    3 комментария
  • Как вы улучшаете "скорость" работы компьютера?

    Jump
    @Jump Куратор тега Системное администрирование
    Системный администратор со стажем.
    Беру CCleaner, чищу реестр.
    Руки оторвать, и выгнать из профессии.
    Дефрагментирую диск
    Отправить лечиться от идиотизма.

    Как вы улучшаете «скорость» работы компьютера?
    Мониторим нагрузку, находим узкие места, устраняем. Т.е добавляем памяти, меняем диск на более быстрый, или компьютер на более производительный.
    Ответ написан
    14 комментариев
  • Как перенести ключи от Github на новый комп?

    martin74ua
    @martin74ua
    Linux administrator
    Можно скопировать .ssh на новый комп.
    Ответ написан
    Комментировать
  • Как организовать массовые выплаты по партнерской программе веб-сервиса?

    @boss_lexa
    https://www.solar-staff.com/partner-network
    выплачивают с помощью иностранных юрлиц, которые не обязаны быть налоговым агентом в РФ и уплата НДФЛ становится обязанностью получателей платежей, а не компании.

    но они с вас еще запросят НДС, тк они не на УСН видимо. поэтому если вы не на ОСН, дешевле вам заплатить 13% НДФЛ, чем 20% НДС
    Ответ написан
    2 комментария
  • Существует ли способ сохранить значение переменной перманентно в php?

    Stalker_RED
    @Stalker_RED
    Что мешает записать токен в сессию, в файл, в мемкеш или в базу данных, например?
    Ответ написан
    2 комментария
  • Какие принципы SOLID здесь нарушены?

    @Flying
    С моей точки зрения здесь в первую очередь нарушается S (принцип единственной ответственности). Box в целом не должен уметь что-то кроме хранения фигур. Как правильно заметил vgbege - из задачи не следует что в дальнейшем вариантов подсчёта каких-то метрик по фигурам с Box'е не станет больше, так что в первую очередь я бы выносил отдельно калькулятор. Также у вас нет обобщающего интерфейса для IArea и IShape из-за чего и возникает путаница в addShape.

    В целом у меня получилось нечто подобное:
    /**
     * Основной интерфейс для всех фигур которые можно хранить в Box'е
     */
    interface IFigure
    {
    
    }
    
    /**
     * Интерфейс для фигур которые могут обладать площадью
     */
    interface IArea extends IFigure
    {
        public function getArea(): float;
    }
    
    /**
     * Интерфейс для фигур которые могут обладать цветом заливки
     */
    interface IFillColor
    {
        public function setFillColor(string $color): self;
    
        public function getFillColor(): string;
    }
    
    /**
     * Обобщённый интерфейс для фигур, обладающих и цветом и площадью
     * По факту, думаю, он не имеет смысла, но нужен по условию задачи
     */
    interface IShape extends IArea, IFillColor
    {
    
    }
    
    /**
     * Коробка для хранения фигур
     */
    class Box
    {
        /**
         * @var IFigure[]
         */
        private $figures = [];
    
        /**
         * @param IFigure[] $figures
         */
        public function __construct(array $figures = [])
        {
            // Добавляем полученные через конструктор фигуры в объект
            // Используем addFigure() чтобы проконтролировать корректность типов
            array_walk($figures, [$this, 'addFigure']);
        }
    
        /**
         * @param IFigure $figure
         * @return $this
         */
        public function addFigure(IFigure $figure): self
        {
            $this->figures[] = $figure;
            return $this;
        }
    
        /**
         * @param IFigure $figure
         * @return bool
         */
        public function hasFigure(IFigure $figure): bool
        {
            return in_array($figure, $this->figures, true);
        }
    
        /**
         * @param IFigure $figure
         * @return $this
         */
        public function removeFigure(IFigure $figure): self
        {
            $this->figures = array_filter($this->figures, static function (IFigure $f) use ($figure) {
                return $f !== $figure;
            });
            return $this;
        }
    
        /**
         * @return IFigure[]
         */
        public function getFigures(): array
        {
            return $this->figures;
        }
    }
    
    /**
     * Интерфейс для калькуляторов фигур в Box'ах
     */
    interface IFigureCalculator
    {
        /**
         * @param Box $box
         * @param mixed ...$args
         * @return mixed
         */
        public function calculate(Box $box, ...$args);
    }
    
    /**
     * Пример калькулятора
     */
    class AreaCalculator implements IFigureCalculator
    {
        public function calculate(Box $box, ...$args): float
        {
            // Получаем список фигур которые обладают площадью
            $figures = array_filter($box->getFigures(), static function (IFigure $figure) {
                return $figure instanceof IArea;
            });
            // Получаем цвет из дополнительных аргументов калькулятора
            $color = array_shift($args);
            if ($color) {
                // У нас задан цвет, фильтруем фигуры по цвету
                $figures = array_filter($figures, static function (IFigure $figure) use ($color) {
                    return $figure instanceof IFillColor && $figure->getFillColor() === $color;
                });
            }
            // Подсчитываем суммарную площадь
            return array_reduce($figures, static function (float $area, IArea $figure) {
                return $area + $figure->getArea();
            }, 0);
        }
    }


    В качестве альтернативы я рассматривал также вариант дать Box'у возможность самому считать метрики через создание у него метода:
    public function calculate(IFigureCalculator $calculator, ...$args)

    но потом решил что лучше не захламлять интерфейс чтобы не усложнять логику.
    Ответ написан
    7 комментариев
  • Какие принципы SOLID здесь нарушены?

    @vgbege
    сразу бросается в глаза O+I я бы сказал
    представь, что после нужно будет считать площадь только маленьких фигур (area < 3) или добавится интерфейс с текстурой и нужно будет считать только пушистые.

    не, формально принцип O пока еще не нарушен, и класс Box можно расширять, добавляя в потомках getTotalAreaSmall и getTotalAreaFluffy. но Box уже сейчас выглядит не просто как Box (который просто хранит фигуры), а как BoxThatCountsColored, а его потомки будут называться BoxThatCountsColoredAndSmallAndFluffy например :)
    Ответ написан
    4 комментария
  • Как управлять запросами к API на клиенте?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Писать свой или искать готовый механизм очереди с контролем времени.

    В очередь (массив) класть запрос (метод, параметры) и callback. Либо промисы.

    Держать массив с временем ответов последних 100 (30) вызовов. Если самый древний более 10 (5) секунд назад, можно выполнить очередной.

    Как-то написал вот такую
    кривую реализацию


    Модуль очереди:
    /**
     * Hold Your Horses!
     * Promise-based dispatcher that respects frequency limits.
     * It queues requests so that no more than N are processed within 1 second.
     * Those can go in parallel.
     *
     * Instantiate the new HH with options, specifying time limit.
     * Method .add(function) adds a new job to the queue.
     * Argument function should return Promise object that starts to process only after the function is called.
     * @return Object Promise.
     */
    
    function HorsesHolder(options) {
      options         = options || {};
      this.rps        = options.rps || 3; // requests per second
      this.parallel   = options.parallel || this.rps; // max parallel running jobs
    
      this.times      = []; // -1: slot is busy, 0: slot is free, positive timestamp - time slot's job has finished
      for (let i=0; i<this.rps; i++) this.times.push(0); // [0, 0, 0] initially
    
      this.queue      = [];
      this.inprogress = [];
      this.debug      = !!options.debug;
      
      this.debug  &&  console.log("%s ms: [HH] initialized", this.ts());
    }
    
    
    HorsesHolder.prototype.add = function(promiseMaker) {
      var self = this;
      
      return new Promise(function(resolve, reject) {
        self.queue.push({
          resolve: resolve,
          reject: reject,
          promiseMaker: promiseMaker,
        });
        
        self._ping();
      });
    };
    
    
    // Decide: work or wait
    HorsesHolder.prototype._ping = function() {
    
      if (this.queue.length === 0) {
        this.debug  &&  console.log("%s ms: [ping] queue is empty", this.ts());
        return;
      }
      
      const best = this._bestTime();
      
      if (best === -1) {
        this.debug  &&  console.log("%s ms: [ping] cannot go: %s", this.ts(), JSON.stringify(this.times));
        return;
      }
      
      const index = this.times.indexOf(best);
      
      this.debug  &&  console.info("%s ms: [ping] exec now at index %d", this.ts(), index);
    
      this._execute(index);
    }
    
    
    /**
     * Out of current times[] finds the best to occupy, if possible;
     * otherwise -1
     */
    HorsesHolder.prototype._bestTime = function() {
      let best = -1;
    
      for (let i=0; i<this.rps; i++) {
        const time = this.times[i];
        if (time === 0) return 0;        // can go now - nothing better!
        if (time < 0) continue;          // previous not finished yet
        if (this.ts() < time + 1000) continue; // not yet
    
        if (best === -1) best = time;
        else best = Math.min(best, time);
      }
      
      return best;
    }
    
    
    HorsesHolder.prototype.ts = function() {
      return (new Date()).getTime();
    }
    
    
    HorsesHolder.prototype._execute = function(index) {
      this.times[index] = -1; // mark busy
      const job = this.queue.shift();
      this.inprogress.push(job);
    
      const self = this;
      
      job.promiseMaker()
      .then(function(r) {
        self.debug  &&  console.info("%s ms: [HH] Job done at index %d", self.ts(), index);
        job.resolve(r);
      })
      .catch(function(err){
        self.debug  &&  console.error("%s ms: [HH err] Error at index %d: %s", self.ts(), index, err.toString());
        job.reject(err);
      })
      .finally(function(){
        self.inprogress.splice( self.inprogress.indexOf(job), 1);
        self.times[index] = self.ts();
        setTimeout(() => self._ping(), 1000);
      });
    }
    
    export default HorsesHolder;


    Модуль работы с VK API:
    /*global VK*/
    /**
     * Function returns Promise for each VK API call.
     * Respects the 3 call per second limit.
     *
     * by Sergei Sokolov <hello@sergeisokolov.com> 2019.
     */
     
    import HorsesHolder from '@/utils/horsesholder';
    
    const debug = true;
    
    const HH = new HorsesHolder({ debug });
    
    
    export default function asyncVK(methodName, data) {
    
    	return HH.add(() => {
    
    		data = data || {};
    		if (!data.v) data.v = 5.92; // VK API version https://vk.com/dev/versions
    		
    		return new Promise((res, rej) => {
    			VK.Api.call(
    				methodName,
    				data,
    				r => {
    					if (r.error) {
    						debug && console.error("[asyncvk] VK API call error:", r.error);
    					}
    					
    					
    					if (r.response) {
    						
    						res(r.response);
    						
    					} else if (r.error) {
    						
    						rej(r.error);
    						
    					} else {
    						
    						debug && console.error("[asyncvk] VK API bad response:", r);
    						
    						rej(r);
    						
    					}
    				}
    			)
    		});
    	});
    }


    Ответ написан
    1 комментарий
  • Возможно ли содержать сервер дома?

    CityCat4
    @CityCat4 Куратор тега Сетевое администрирование
    //COPY01 EXEC PGM=IEBGENER
    Что-то последнее время стало много вопросов на эту тему...

    Ну ладно, еще раз, как человек, уже больше года держащий дома самый настоящий серверный сервер (а не рабочую станцию, работающую сервером) выскажу свое мнение.

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

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

    К сожалению, плюсов не бывает без минусов :) Хотелось бы о них тоже поподробнее - не чтобы отговорить, а чтобы предупредить.

    - Цена, комплекутха, ЗиП. Новое серверное железо очень дорогое. Сервак за пол-лимона - это как здрассьте. "Для себя" обычно берут бу железо. Это довольно распространенный метод, так что существуют специальные конторы, торгующие бу серверным железом. Насколько оно старое? Обычно не моложе пяти лет. Почему пяти? В крупных конторах есть регламенты, по которым железо списывается по истечении определенного срока, обычно он пять лет. Списывается, независимо от состояния, даже если оно идеальное. Бу сервер можно прикупить за вполне приемлемые деньги (разумеется имея в виду, что винты нужно брать новые и не десктопные, а именно рейдовые). Комплектуху и ЗиП покупать можно в тех же конторах.

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

    - Шум. такого понятия как
    тихий серверный шкаф

    не существует. От слова совсем. Потому что шкаф - для серверной. Даже самый тихий сервер (а я подбирал именно по "тихости") даже при самых низких оборотах кулера (в BIOS - 4500 об/мин) - довольно заметно шумит. Кроме того, если температура повышается, сервер автоматически кладет на настройки BIOS и повышает скорость вращения кулеров - в итоге у меня сервер в людбое время устойчиво негромко гудит и периодически взвывает - потому что перегревается.

    - Комфортная температура. Для сервера и человека - она разная и поэтому запросто получится, что Вам придется выделить серверу отдельную комнату :D

    - Елестричество. Сервер жрет электричество. Круглые сутки, как дозорный в будке. Готовьтесь к повышению счетов от энергосбыта. Кроме того, сервер без упса будет падать при просадках - а в домах они не редкость. (У меня тоже нет упса :( )

    - Изнашиваемые части. Про ЗиП было уже сказано - так вот, не забывайте, что сервер содержит части, которые ломаются :) Кулеры, винты - все это нужно будет покупать :)

    - Интернет-канал. Для физиков как правило flat-rate не предоставляют (ну либо заломят, как с юрика), поэтому держать там нагруженный сайт Вы не сможете - он будет адово тормозить. Хотя обычный сайт работать будет (если пров дает белые IP).

    - Анти-вирус, анти-ддос, анти-спам, анти-все-остальное. Все это придется делать самому либо просто забить. Разумеется, профессиональному админу это сделать несложно.

    - Настройка, резервное копирование. Фактически повторение предыдущего пункта - спихнуть нее на кого, сами, все сами...

    - Изменить IP практически невозможно, уж не говоря о его регулярной смене.
    Ответ написан
    12 комментариев
  • Какой стек использовать, React+...?

    freislot
    @freislot
    Frontend-разработчик
    Node.js+Express+MongoDB+React я бы копал куда-то сюда
    Ответ написан
    1 комментарий
  • Какой стек использовать, React+...?

    Robur
    @Robur
    Знаю больше чем это необходимо
    Раз у вас вообще нет никаких требований - то возьмите что-нибудь веселое, Fortran какой-нибудь, или хотя бы Erlang.
    Ответ написан
    Комментировать
  • На youtub есть канал где читают код PHP?

    hack504
    @hack504
    Изучаю PHP рекомендуют читать чужой код.

    Даже спецы не читают чужой код, если их не заставят. Но было бы прикольно, действительно, посмотреть на youtub как разрабы читают чужой код, особенно на PHP
    1387209829_1176468776.gif
    Ответ написан
    10 комментариев
  • Возможно ли на локальном сайте сделать выход в интернет?

    Zoominger
    @Zoominger Куратор тега Веб-разработка
    System Integrator
    Не понял.
    Если вы подняли сайт на локальном сервере, вы можете через JS подгрузить туда хоть котиков, хоть goatse.
    Если есть Интернет.
    Ответ написан
    2 комментария
  • Где заявить о своём продукте?

    Alex_Wells
    @Alex_Wells
    PHP/Kotlin
    И чем эта тудушка лучше банального google keep? У меня в телефоне в три раза больше функционала, красивые анимашки и плюшечки, чем в вашем проекте.

    Просто сделать какой-то продукт и просто отрекламить - недостаточно. Нужно правильно спроектировать продукт и показать, насколько он крутой и молодежный, насколько он круче других тудушек - но судя по описанию, этого нет, а значить и смысла рекламить - тоже.
    Ответ написан
    Комментировать
  • Побег на Линукс?

    @deliro
    7. Фото и видео редакторы.

    До свидания, линукс. Привет, мак
    Ответ написан
    8 комментариев
  • Как узнать, активизирована ли у пользователя функция - без перекрестного отслеживания?

    lazalu68
    @lazalu68
    Salmon
    Насколько я понял, в window.navigator об этом никакой инфы нету. А раз нету, то придётся по каким-то конкретным признакам определять запрещает ли браузер отслеживание, например через печенюхи. В любом случае, из найденных материалов мне показалось, что опция "Prevent cross site tracking" просто врубает ITP 2.x, о котором в интернетах достаточно инфы. Один из способов который я вижу основывается на том, что фрейм обращающийся к подконтрольному вам ресурсу сообщает родительскому документу получилось ли у него достучаться до каких-то важных печенюх или нет.

    ЗЫ: либо я нашел решение, либо одно из трёх - ITP 2.0 вводит метод document.hasStorageAccess, соответственно можно проверять какое значение возвращает этот метод и уже от этого плясать. Вот тут чувак накатал небольшой скрипт для подобной проверки. Проверил на восьмом ифоне этот метод, он возвращает false если опция "Prevent cross site tracking" выключена, и true - если включена.

    Если "Prevent cross site tracking" это действительно только об ITP 2.0 и вдобавок я нигде не ошибаюсь в рассуждениях, то функция проверки может выглядеть как-то так:

    async function ITPIsActive() {
    	if (document.hasStorageAccess && document.requestStorageAccess) {
            const access = await new Promise(function(res, rej) {
                document.hasStorageAccess().then(res, rej).catch(rej);
            });
    
            return access;
        } else {
            return false;
        }
    }
    Ответ написан
    1 комментарий
  • Где искать Middle/Senior backend Node.js разработчиков?

    @MasterMike
    Вопрос не в том, где они тусуются.
    Вопрос в том, что вы им готовы предложить )

    upd. Ну и это, "сильно благодарна" - это сколько в $? )
    Сколько там нынче берут за хант программиста средней руки, полторы его зарплаты или больше? )
    Ответ написан
    Комментировать
  • Почему React разработчики не пишут циклы for, while?

    toxicmt
    @toxicmt
    CTO at hexlet.io
    Если очень узко, то функция `map` в отличие от цикла "отображает" набор, то есть обрабатывает каждый элемент и возвращает новую коллекцию. Именно это нужно делать когда мы работаем с JSX. А циклы это не функции, которые могут возвращать значения, это конструкция языка с помощью которой, например, можно собирать переменные. Из-за того что JSX это декларативная штука (мы описываем ее как есть, а не получаем в результате вычислений), циклы туда просто не встроить.

    Циклы это пример императивного программирования, в то время как функции высшего порядка (filter, map, reduce) – декларативного (функциональный подход). Второй подход в js более канонический (ближе к функциональным языкам) и позволяет писать гораздо более понятный и лаконичный код. При условии, конечно, что вы знакомы с этой парадигмой.

    Кстати в декларативном коде не используют переменные (если писать правильно), они там просто не нужны. Только константы.

    Вот посмотрите код из бекенд проекта в котором нет ни одного цикла: https://github.com/Hexlet/hexlet-exercise-kit/blob...
    Ответ написан
    5 комментариев
  • Почему React разработчики не пишут циклы for, while?

    hzzzzl
    @hzzzzl
    hulktoster, map/filter/reduce делают как раз то, что надо в реакте - преобразовывают массив с данными в массив с компонентами реакта, можно конечно и через циклы, но это будет больше писанины и будет менее наглядно

    data = [........]
    
    render() {
      return (
      <>
        { data.map(x => <MyComponent prop1={x.prop1} prop2={x.prop2} />) }
      </>
      )
    }


    data = [........]
    
    render() {
      const components = []
      for(let i = 0; i < data.length; i++) {
        const x = data[i]
        components.push(<MyComponent  prop1={x.prop1} prop2={x.prop2} />)
      }
    
      return (
      <>
        { components }
      </>
      )
    }


    и это только если надо что-то замапать, а если еще фильтровать итд, то строк в цикле больше и больше
    Ответ написан
    Комментировать
  • Профессия веб-дизайнер мертва?

    Zoominger
    @Zoominger
    System Integrator
    А что такое "обычный веб-дизайнер"? Формошлёп, знающий, как слепить страницу? Так это любой конструктор уже умеет.
    Веб-дизайнер сейчас - это не просто клавиатурный осьминог, это помесь маркетолога, веб-программиста, дизайнера и бизнес-логиста, который будет взаимодействовать с командой интересных специалистов, если речь идёт о крупном сайте. Мы не говорим, конечно, про вайтишников.
    Ответ написан
    7 комментариев