Каркас, созданный для решения проблем деградации кода проекта на моей прошлой работе. Не был применен. Попытка добиться низкого зацепления и соблюдения SOLID.
Вот часть каркаса на уровне соглашений и философии, а не кода: https://docs.google.com/document/d/1Tc1BZ2ku3oxKspuPloulO0NEEZo-4w1VHAYz5pvQEpI/edit
Или кратко она же - ниже.
Простые вещи:
- Класс по умолчанию final (прописать в шаблоне IDE)
- DI только через конструкторы
- Аттрибуты только private
- Нет - кодам ошибок, да - исключениям
- Можно только одноуровневые обычные или ассоативные массивы
- Unit tests:
- предусловия и постусловия теста должны быть кристально ясны перед его написанием
- разумная индукция значений входных и выходных данных
- Писать интерфейсы для Yii и сторонних компонентов
- Одна модель и один вид в каждом контроллере (HMVC)
- JS компоненты общаются только через события
- RequestManager используется только в контроллерах
- Юзать "..." вместо массивов, где возможно
SOLID:
- Через new можно создавать только объекты-значения без инъекций. То же касается и статических методов
- Объекты-значения не должны иметь зависимостей не только от других программных конструктов, но и от внешних ресурсов: файлов, папок, чего угодно
- if-elseif/switch не нужен, полиморфизм рулит
- Типы, типы everywhere. Где нельзя, assert-ы
- Наследование нужно:
- для семейств объектов с одинаковым API, но разной реализацией - принцип фреймворка
- для создания иерархий типов Иначе композиция
- Неиммутабельность объекта, если неоправданно сложна иммутабельность, иначе иммутабельность Мутабельные объекты помечать как @mutable
- protected методы тестируются, как и public (setAccessible)
Соглашения:
- @uses Yii метка, где используется Yii
- @inversion Метка для любой инверсии управления
- @uses db Метка для методов, в которых происходит обращение к БД средствами Yii
- Одинарные кавычки в строках PHP без переменных и JS строках
- Пути:
- См. ExampleView, ExampleController
- AutoAlliance\Domain
- AutoAlliance\Technology
- *\Value для объектов-значений. Объекты-значения - простые объекты-типы в составе других-объектов, "объекты низкого уровня". Примеры: Email, Uri, PhoneNumber
- Порядок членов класса: const, static, vars, abstract public, public, abstract protected, protected, private and vars-caches
Именование:
- Не использовать сокращения в названиях
- В аббревиатурах только первая буква - заглавная
- Ассоциативные массивы и методы, их возвращающие, получают постфикc *Map
- Всегда единственное число
- *Controller *PackageFactory *Interface *Trait *Exception *View *Strategy, *Factory, *%SomePattern%
PHP запреты:
- Magic methods
- Ссылки
- Строки и конкатенация для динамического создания имен программных конструктов
- compact
CSS:
- Сперва - представление, затем через строку - позиционирование
JS:
- Использовать Object.defineProperty
- js-* для классов для JS, на них нельзя вешать CSS
Как писать для БД:
- Active Record содержит всю работу с данными, модель, наследующая ее - всю бизнес-логику
- Создается интерфейс для модели
- В модели явно описаны переменные, которые появляются от Active Record, доступ к ним снаружи - только через интерфейс. Помечаются @ar. Модель может иметь доступ только к этим свойствам, весь API Active Record ей недоступен
- Обращение к БД только в контроллерах и избранных библиотеках, изолировать их в отдельные методы
- Использовать СActiveForm, а CHtml нельзя
- Валидация как обычно в Yii
Как создавать типы:
- Конструктор содержит условия существования объекта - инвариант класса. Например File - в конструкторе assert is_file
- Наследование + трейты или интерфейсы более-менее дают множественное наследование типов
- PROFIT, типы здорово повышают устойчивость программы, т.к. главная беда ошибок - их запоздалая локализация в коде
Стратегия касаемо устойчивости кода к ошибкам:
- Тестируется только код с нетривиальной логикой
- Остальная надежность отдается на откуп типам и ассертам
- На OCP забить, а на SRP - нет, за счет чего OCP будет нарушаться нечасто
Как проводить рефакторинг проекта:
- Разбивать на минимальные итерации. Ключевое понятие - шов, т.е. линия, по которой интерфейсами и адаптерами новый код отделяется от старого
- Опрелить, какой класс переписывается, а для какого пишется адаптер/интерфейс
- Адаптеры/интерфейсы должны быть адекватными, без реверансов существующему коду; обратить особое внимание на SRP
- Проектирование, реализация, PROFIT
Как работают клиентские пакеты:
- Изучите все названия классов в ClientPackage/Core, используйте
- Региструются они автоматически
- Основная фишка - автоматическая загрузка JS/CSS в директории класса-фабрики клиентского пакета, прописывать вручную файлики не нужно
Как работать с PostCSS:
- Обратитесь к кому-нибудь из коллег за актуальным PHPStorm watcher-ом
- Используйте $style в шаблонах
Когда использовать assert-ы, инварианты класса, исключения, а когда валидацию:
- Инвариант класса: недопустимая ситуация, ошибка работы приложения
- Assert: то же, что и 1, но нельзя использовать инвариант
- Исключение: непредстазуемая ситуация, для которой необходима возможность обработки
- Валидация: необходима возможность вводить некорректные данные, ошибка как часть логики работы приложения, а не исключительная ситуация
P.S. Всегда возможны исключения
Еще документы:
- https://docs.google.com/document/d/1Tc1BZ2ku3oxKspuPloulO0NEEZo-4w1VHAYz5pvQEpI Эссе про программирование
- https://docs.google.com/document/d/1YYiYJZ9oIP5uWY3vK6F1C_2MAQeUkL8czSRJSHTy1cM Устаревшая и более подробная версия этого документа
- https://habrahabr.ru/post/336788/