• Где найти паттерны "правильных" частей системы?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Вот проектируя большой проект с нуля ты уже оперируешь не паттерновыми объектами а частами систем


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

    Большие проекты начинают проектировать с более высокого уровня. Сначала принимают решение о том, какое разделение на слои у нас будет (для проектов со сроками жизни ~10+ лет имеет смысл позагоняться и вводить гексагональную архитектуру, для проектов со сроками жизни <= строк поддержки фреймворка можно не сильно париться), какие компоненты можно выделить, а уже потом дробить эти большие компоненты на компоненты поменьше.

    Затем уже приступать к проектированию каждого отдельного компонента на уровне классов.

    Так же если у нас сложная предметная область - проектируют модель предметной области. Обычно тут "паттерны" сами собой получаются тупо при снижении связанности между объектами.

    > Собственно вопрос: существует ли сборник всех этих лучших практик?

    вне контекста не бывает лучших практик, есть просто практики. В этом плане можно например Фаулера почитать, он очень качественно описывает практики, их плюсы и минусы.

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

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Каков рецепт изучения новых языков/технологий?


    Сначала хорошо ищучите парочку тех что уже знаете.

    Стоит ли мне для изучения Ruby далее или Tornado, или Angular читать об этом целую книгу, которая будет много говорить о философии этого инструмента, как он устроен? Или стоит искать какие-то поверхностные методы?


    Нет ничего быстрее документации.

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


    RTFM
    Ответ написан
    2 комментария
  • Как с помощью underscore разделить массив по 10 элементов?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    не совсем при помощи lodash... но

    function chunk(arr, n) {
        var chunks = [];
        while(arr.length > n) {
           chunks.push(arr.slice(0, n));
           arr = arr.slice(n, arr.length);
        }
        chunks.push(arr);
    
        return chunks;    
    }
    Ответ написан
    Комментировать
  • PHP Abstract Registry или методы __set() and __get(), как лучше реализовать глобальную переменную?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Какой вариант предпочтительнее? Страшно ли объявление как в первом варианте? Или как лучше поступить?


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

    1) контроллер не должен иметь состояния
    2) view так же не должно иметь состояние, ему на вход приходят данные и оно его тупо рисует.
    3) модель - единственное что может иметь состояние, но если что это не один объект, это целый граф объектов. Сущности, сервисы и объекты-значения.

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

    Затем мы это состояние из контроллера скармливаем в шаблонизатор какой и получаем view. Замечу что view в контексте вопроса это просто пассивное отображение данных на HTTP.

    Вывод - глобальное состояние не нужно.
    Ответ написан
  • Что за магия в symfony?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Что-то как-то теряется смысл контроллера, как посредника между моделью и видом.


    1) Symfony - не MVC фреймворк, это request/response фреймворк. Более правильная терминология для HTTP фреймворка.

    2) Контроллеры - это не один класс, это в данном случае весь слой от точки входа, фронт контроллера, до непосредственно экшена контроллера. View в этом случае - это HTTP, пассивная вьюшка и только. Сама по себе она ничего не умеет, это тупо представление данных собранное контроллером.

    У этого подхода есть название - Model-View-Adapter или Mediating-controller MVC, но все это лишь бесполезные детали.

    3) ParamConverter-ы здорово уменьшают дублирование кода в контроллерах, однако работа с сущностями в контроллерах дело довольно опасное. Это своего рода компромис между "правильной архитектурой" и "стоимостью разработки.
    Ответ написан
    Комментировать
  • Какой смысл от синглтона, когда есть статика?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Ведь в любом случае мы получаем глобальное состояние


    А глобальное состояние что? Правильно, плохо. У меня тут недалеко есть один небольшой проектик под iOS где ребята решили повесилиться, и сделали сингелтон с сотней публичных свойств. И вся система работает с этим глобальным состоянием плодя побочные эффекты. Инкапсуляция? не, не слышали.

    Какой смысл использовать именно singleton?


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

    В PHP, где не не особо популярна идея многопоточного программирования, и процветает "умирающая" модель выполнения, в сингелтонах вообще нет смысла. И используют их потому что... внимание... хотят иметь глобальный доступ к различной фигне, в том числе организация глобального состояния.
    Ответ написан
    6 комментариев
  • Docker. Почему при переключении на другого юзера пропадает переменная окружения?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Когда захожу во второй контейнер и переключаюсь на юзера docker переменная PATH сбрасывается


    Ну так вы сменили "окружение" по сути. Единственный способ этого избежать - записать ее в /etc/environment.

    В целом же проще будет просто поместить ваш бинарник в /usr/local/bin например.
    Ответ написан
    Комментировать
  • Как правильно сделать аутентификацию на php?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Погуглив, я посмотрел исходники Yii, Симфони и PHPixie, чтобы узнать, как аутентификация сделана у умных людей


    Не забывайте, что в фреймворках это все сделано с одним расчетом - покрыть 95% возможных юзкейсов. А в связи с этим реализация чуточку сложнее. Так же не стоит забывать, что все это "должно" работать на php5.4+, а, например password api появился только в 5.5, а хэширование пароля это целая наука.

    Давайте разложим задачу на под задачи:

    Нам нужно проверить введенные пользователем данных. Это может быть пара идентификатор + какой-то секретный ключь (email + пароль если проще), а может это просто секретный ключ (токен), или JWT токен... словом вариантов тут много, но нам пока нужна пара старых добрых email + пароль.

    Для этого в PHP есть весьма простая в использовании апишка для работы с паролями: password api. Используйте только ее (или что-то что ее под копотом использует) ибо это самый безопасный и надежный способ работы с паролями в PHP. Обязательно прочитайте этот раздел документации.

    В очень простом случае (коих большинство) вам при регистрации нужно просто загнать строчку в password_hash и получить на выход новую строчку, которая пишется в базу. При логине мы забираем пользователя с указанным email и проверяем введенный пароль через функцию password_verify.

    После того как мы убедились что пользователь не выдает себя за другого, мы можем создать сессию. В самом простом случае мы просто создаем сессию с ID юзера и... собственно все. идентификатор сессии будет записан в http-only куку и все здорово. Правда при работе с сессиями в PHP нужно помнить про CSRF атаки, от которых нужно защищаться (что умеют практически все фреймворки из коробки).

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

    p.s. поскольку этот вопрос весьма щепетильный, и ля того что бы сделать все это "безопасным" нужно порядком опыта, я рекомендую вам разобраться с фреймворками или готовыми популярными библиотеками.
    Ответ написан
    1 комментарий
  • Как сделать многопоточный чат?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    у вас должен быть один основной поток, где вы ожидаете подключения. При подключении у вас создается сокет, который вы кидаете в отдельный тред.

    Socket clientSocket = serverSocket.accept();

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

    Хочу отдельно отметить, что при увеличении количества потоков производительность будет падать. При достижении отметки в пару сотен клиентов например. В этом случае лучше переключаться на event loop/микротреды/корутины.
    Ответ написан
    1 комментарий
  • Macbook Pro 13" (2015) для разработки ОК?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Для серьезной разработки - нет. Даже air слабоват. Все упрется в процессор. Но для обучения - норм.

    если нужно именно писать код

    Писать код - это малая часть того чем занимаются программисты. Вам этот код еще запускать надо. И чем серьезнее разработка - тем больше ресурсов требуется. Сначала это просто ruby, потом добавляются различные системы сборок, потом окружение изолировать придется (docker-ы всякие), и так постепенно задачи будут все более усложняться.
    Ответ написан
    4 комментария
  • Зачем подавать данные в json?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    json - это удобный формат сериализации данных. Возможность сериализации/десериализации в json есть буквально во всех языках программирования что делает этот формат довольно универсальным.

    Если вы не будете его использовать - вам придется реализовывать что-то другое. Это могут быть другие форматы сериализации, например messagepack, или если хотите, запаковывайте данные сами так как хотите, в зависимости от задачи. Но в этом случае вам придется реализовывать сериализацию самостоятельно, а это время. А время это деньги. Потому это должно окупаться (например что бы увеличить пропускную способность использовать свой бинарный формат сериалиализации разработанный исключительно под задачу, хотя это оооочень редко нужно и я сомневаюсь что вам это понадобится ближайшие лет 5-10).
    Ответ написан
    Комментировать
  • Для каких целей используется директория upload/?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    давайте думать... у нас есть название "upload". Даже если вы по каким-то причинам не знаете как переводится это слово, достаточно заглянуть в словарик:

    upload - загружать

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

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Кусать локти. Сомневаюсь что за вами закреплено какое-то юридическое право за этой идеей.

    Вам остается только вкладывать больше в маркетинг и развивать проект что бы переманить аудиторию.
    Ответ написан
    Комментировать
  • Концептуальные темы, книги, без привязки к языку, кто какие знает?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    - Функциональное программирование - концепция не привязанная к языку
    - ООП - концепция не привязанная к языку (даже если у вас чисто функциональный язык программирования вы можете "эмулировать" объекты для сокрытия состояния).
    - Тестирование кода - не привязано к языку. Так же как и подходы вроде TDD и BDD (тут хорошо Кент Бэка подходит)
    - DDD - не привязано к языку (читать Эрика Эванса)
    - Рефакторинг (Мартин Фаулер)
    - Архитектура приложений (про SOLID читаем у Роберта Мартина, про GRASP - у Крэйга Лармана. Так же есть всякие "программист-прагматик" дэйва томаса и т.д. Ну и опять же Фаулер)
    - Базы данных - вообще не привязано к языку.

    Можно так долго продолжать. По сути добрых 90% всего не привязано к языку.
    Ответ написан
    Комментировать
  • Нужно ли запрещать git push origin master -f на уровне репозитория?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    1. Перезапись истории нужна, но ее нужно использовать осторожно. Пуш с форсом в мастер - исключение из правил, и в вашей ситуации это полностью оправдано.

    2. В 99% случаев спасает реверт. В остальных случаях - push --force, но это крайне редко.

    В целом я фанат rebase-ов, что бы история гита была линейной. Если фичабрэнч не fast forward то ребейзимся на мастер и перезаписываем историю этой ветки. Ну а далее fast-forward merge (а еще лучше - сквошить коммиты перед этим). Но тут могут быть несогласные, потому использую те варианты которые приняты в команде.
    Ответ написан
    Комментировать
  • Как получить родителя и потомка из пути на php?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    function getPathTree(string $path) : array
    {
        $paths = [$path];
        while('/' !== $path=dirname($path)) {
             $paths[] = $path; 
        }
        return array_reverse($paths);
    }
    Ответ написан
  • Как найти пересечение массивов?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    $ids1 = array_column($result1, 'id');
    $ids2 = array_column($result2, 'id');
    // ...
    $idsn = array_column($resultn, 'id');
    
    $intersection = array_intersect($ids1, $ids2, ..., $idsn);


    Или если упростить:

    $ids = array_intersect(
        ...array_map(function(array $collection) {
             return array_column($collection, 'id');
        }, $results)
    );


    updated:

    $result = null;
    foreach($sql_queries as $sql_query) {
      $query_result =  $wpdb->get_results($sql_query);
      $ids = array_column($query_result, 'id');
      if (null === $result) { 
          $result = $ids; 
      } else {
          $result = array_intersect(
                $result, $ids
          );
      }
      $result = array_merge($result, $query_result);
    }
    Ответ написан
    2 комментария
  • Как правильно реализовать фасад?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    хочу спрятать создание объекта и вызов его функций за фасадом.


    Это не фасад, это service locator, глобальный доступ к зависимостям. Не делайте так, используйте IoC, например PHP-DI. Даже в laravel потихоньку от этой сатаны отказываются.

    Фасад - это когда мы берем несколько интерфейсов, и строим над ними один попроще.
    Ответ написан
    Комментировать
  • Паттерн Repository и Active Record?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Что такое репозиторий? Это что-то что отвечает за хранение данных. Целиком и полностью. То есть вот простенький интерфейс простенького репозитория:

    interface UserRepository {
        public User getUser(UserID id);
        public void add(User user);
        public void remove(User user);
    }


    Где именно репозиторий хранит данные, в базе данных, в памяти, в файлах, на удаленном сервере с запросами через http - это все детали реализации. То есть репозиторий - это паттерн для того, что бы абстрагировать наш код от места хранения данных.

    Репозиторий который умеет только выборки делать - это не репозиторий. Это штука для выборок, Finder. Так же мы должны тут заметить, что "строками таблиц" является объект типа User, а репозиторий представляет собой абстракцию от таблицы (очень упрощенно. есть еще паттерн table data gateway который отвечает именно за одну таблицу, репозиторий же может хэндлить и связи между таблицами и вообще оперирует именно объектами предметной области а не их отображением на базу).

    Active Record же делает именно то, что говорит название. Это объект, который представляет собой одну строку из таблицы. Он сам может себя вставить, обновить или удалить из таблицы. Однако "найти себя" он не может к примеру, за это отвечает какой-то другой объект (мне нравится название Finder, поскольку это именно то что делает объект - ищет наши строки таблиц). Частенько для упрощения методы файдеров делаются как статические методы.

    По сути ActiveRecord есть ничто иное как упрощенная комбинация из Domain Object + Row Data Gateway.
    Ответ написан
    Комментировать
  • Обязательно ли в коде придерживаться стандарта ширины строки в 80 символов?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Это правило необходимо для того, что бы код удобнее читался (что бы не приходилось пользоваться горизонтальным скролом, и вертикального хватает). Вглянул на код - и все видно.

    Других причин следовать этому правилу особо нет. Я стараюсь придерживаться этого правила и для html, делая переносы строк в случае с большим количеством аттрибутов.
    Ответ написан
    Комментировать