IDE
PHPStorm, конечно. На самом деле меня уже пугает эта монополия, потому что многие плюшки завязаны на него одного, и при переходе на что-нибудь другое куча времени уйдет не на переобучение, а просто на пересоздание функционала. Из рюшечек, которые используются не так часто:
- File Watcher + Codeception + промежуточный shell-скрипт (если есть tests/Unit/$файл$Test.php - прогнать его) = автотесты, которые упадут с ошибкой в случае чего. Не сказать, что спасло меня хоть раз, но сознание приятно будоражит
- Стек run configurations - почти что ci-джоба. Можно настроить себе всё тестирование и анализ одним стеком и запускать за час до конца рабочего дня.
- Запуск тех же конфигураций в режиме отладки позволяет залезть прямо в тест и посмотреть, что упало. По-хорошему так делать нельзя, по-хорошему надо делать такие отчеты для тестов, чтобы в них можно было установить первопричину падения, но у нас же никогда нет времени.
- Подключение coverage.xml и подсветка еще не покрытых строк.
- Рефакторинг - абсолютно божественная штука
- Кодогенерация (alt + insert) - как правило, использую только для геттеров/сеттеров и все равно парвлю PHPDoc, но очень уж приятная штука
- Не знаю как в других IDE, но в PHPStorm довольно приятная поддержка неймспейсов
- Интеграция PHPMD/PHPCS прямо на уровне подсветки кислых строк.
- Проверка файлов перед коммитом - очень полезная штука, хоть я и могу ее нормально использовать только в своих проектах (времени, к сожалению, не хватает на работе).
Веб-сервер
nginx. До сих пор свободно не ориентируюсь в конфигах, но с ним как-то легче, чем с апачем (гори в аду, .htaccess) + в 99% случаев на продакшене будет именно он. PHP-FPM настроен на три конфигурации - dev, test, prod, но ни разу это серьезного буста не придало. Конфигурирую руками, что неправильно примерно на все 100% - я до сих пор не знаю, как это должно быть в идеале (vagrant? docker? virtualbox + chef/puppet/saltstack?), но руками это дело делать нельзя. В свое время была идея написать простенький консольный конфигуратор веб-сервера, но проект успешно заглох - чтобы реализовать его полностью, мне нужно сначала дописать еще пару либ, которые благополучно стоят на месте.
OS
Linux Mint / KDE. Просто личное предпочтение. Ну, на самом деле на домашнем стационарнике по ряду причин винда 8, но в виртуалке - Linux Mint. By the way - собственное окружение также стоит организовывать через какой-нибудь puppet, потому что очень болезненно все накатывать в пятый раз вручную.
Расположение исходников
Я по-своему долбанутый, поэтому держу такую структуру:
- /srv/http/src - реальные сорцы веб-проектов
- /srv/http/hosts - симлинки на сорцы по названиям хостов (например, в сорцах может валяться проект playground, а в хостах - playground.dev, admin.playground.dev, special.playground.dev)
- /srv/http/apps - всякие pma, которыми я прекратил пользоваться
- /home/etki/Workspace - папки с симлинками на сорцы + собственные проекты, которые не требуют веб-сервера (библиотеки)
- /usr/local/bin/composer - композер
- /usr/local/composer - глобальная папка композера
- /var/cache/composer - кэш композера. Вкупе с предпоследней папкой превращают глобальную видимость композера из user-wide в system-wide
- /usr/local/composer/vendor/bin - добавляется в PATH
У нормальных людей вместо /srv/http используется /var/www
хосты организую с помощью dnsmasq (просто добавил резолв в 127.0.0.1 для tld loc, local, dev, prod, test)
Библиотеки, фреймворки и утилиты
В ходе последних месяцев было установлено следующее:
Для PHP есть порядочно клевых утилит для тестинга и анализа кода - уже упомянутые phpcs и phpmd, phpcpd, phpdcd, php docblock checker (это для таких зануд, как я), parallel lint, pdepend, phploc, которые многое могут сказать о коде. php-cs-fixer вам еще и поправит код. Конкретно для тестинга - athletic, codeception, первый по понятным причинам используется редко, но когда его удается применить, радуюсь, как ребенок.
Opencart, Yii, Yii2, CI, Kohana, Wordpress, Joomla - лютое, непробиваемое, которое нельзя использовать никогда. Yii2 - разочарование года, казалось бы, все костыли уже известны, но все равно там на каждом шагу какие-то грабли.
Прямо сейчас стоит проект, которому открутить бы Yii и подставить Symfony. Это уже невозможно, но если бы я делал миграции на Phinx (а я же умею, блин) и изначально писал более портабельный код, я бы таки смог перепрыгнуть между итерациями за эти новогодние праздники.
Любая апишка должна писаться через guzzle. Это банально отбивается по времени. Кроме того, mock plugin на раз-два позволяет вторгнуться в ход выполнения и подсунуть свой ответ, что позволяет разрабатывать клиента апишки, не трогая саму апишку. Еще один гвоздь в текущий проект.
На packagist лежит несколько пакетов виртуальной файловой системы. Потребуется время, чтобы в них вникнуть, но с этой штукой можно тестирование прямо взлетает на новый уровень.
Mock (неважно, от какой из библиотек, PHPUnit, Mockery, Codeception/Stub) - лучшее изобретение человечества. Это опять упирается в мой любимый тестинг, но когда я наконец начал использовать всю связку этих волшебных практик, я наконец-то понял, как и зачем пишется несвязный код (и почему отвратительнее богообъекта Yii не может быть ничего).
Везде, где нет шаблонизатора или есть выбор, лучше использовать Twig. Он и руками прикручивается строчек за пять кода, и снимает большинство головной боли - хочешь, наследуй шаблоны, хочешь, реализуй привычную layout-систему.
Практики написания кода
Статичные методы действительно нельзя использовать. Потому что если конкретный объект еще можно подменить, то статичный вызов всегда зависит от имени класса, что намертво вбивает зависимость в код. Это уже и не оттестить, и не отрефакторить в короткие сроки. Можно, конечно, использовать $className::method()
, но лично у меня от такого глаза на лоб лезут. Любой простенький контейнер позволит вам проинициализировать объекты один раз и быть уверенным в производительности кода.
ВСЕГДА, ВСЕГДА реализовывать поддержку dev / prod / test окружения, даже если этого нет в фреймворке. Когда проект раздувается до десятка апишек, внедрять эту штуку уже поздно, потому что все излишки уходят на быстрый (а значит, плохой) рефакторинг.
Всегда, когда это возможно, должна вводиться поддержка feature flags и dev traits (по большому счету, это одно и то же, dev traits я вообще сам для себя выдумал). Feature flags - это просто набор флагов (булевых значений) в конфигурации, который управляет тем, включены или выключены определенные фичи. Это позволяет включать и выключать фичи мановением руки, и в деве фича может нестабильно, но работать, а в проде быть выключена вообще. Или работать стабильно, но ожидать ревью от отдела тестирования. Dev traits - это тоже набор флагов, который работает только в dev-окружении и управляет дополнительным поведением приложения, облегчающим разработку: заполняет формы, скрывает элементы и т.п. В моем текущем проекте эта штука спасла меня, когда пришлось переводить гигантский лендинг - я научил компонент перевода подкрашивать токены разным цветом в зависимости от того переведены они, или нет, а вместо пустых вызовов ставить красную заглушку об отсутствии токена. Еще один флаг позволяет скрыть перевод вообще к чертям, что позволяет мне увидеть только непереведенный текст.
Ни один конфиг на свете не должен писаться на PHP (привет еще раз, Yii!). Это просто отвратительно, такой конфиг невозможно толкого записать в файл еще раз. Даже если восстановить структуру массива, потеряются все выражения и инклюды. Один из моих ожидающих свободного времени сайд-проектов - это конфигуратор на основе yaml, который поддерживает простенькие expression'ы типа !include file.yaml
/ !realpath src
/ !instantiate \Vendor\Lib\Class
, который наконец позволит мне комфортно работать с Yii (ну а с чем же еще).
Я выше уже писал про миграции - на любом проекте, который не использует разворачиваемую из коробки структру бд, они должны использоваться; любой шаг в сторону карается насквозь простреленной ногой. Я как-то спрашивал, насколько атомарны должны быть миграции - ну так вот, они должны быть максимально атомарны, одно изменение - одна миграция. Когда в одной миграции создается таблица, а затем последующее создание foreign key проваливается - это простреливает и вторую ногу. Плюс вообще все мигарции должны писаться с расчетом на присутствие данных - вы не сможете сделать столбец уникальным, если там уже висят неуникальные значения.
Interfaces first: везде, где предполагаются имплементации, все должно зависеть от интерфейсов. Это довольно тонкий момент, на вербализацию которого у меня не хватит способностей, но если вкратце на примере: клиент апишки должен обрабатывать не HttpResponse
, а HttpResponseInterface
. В этом случае смена библиотеки, осуществляющей сетевые запросы превращается из перекапывания всех уровней написанного кода в написание тривиального враппера, который будет удовлетворять требованиям HttpResponseInterface
. Насколько понимаю, именно это и есть D в SOLID. Ну и согласно I - ни один интерфейс не должен вбирать в себя миллион методов. Пока я не узнал про мок-плагин для guzzle, я собирался писать аналогичный функционал, который бы обходил guzzle целиком и возвращал бы ResponseInterface
-объект (простого мока тут явно не хватило бы). Когда я увидел, что там придется реализовывать порядка пятнадцати методов, о 70% которых я не имею ни малейшего представления - мне порядком взгрустнулось.
Как правило, любой проект практически заставляет писать свои исключения. В этом случае есть очень полезный хак, который позволяет установить обработчик исключений только на исключения данной библиотеки, и при этом сохранить традиционную цепочку наследования. Делается это так:
Пишется пустой интерфейс
interface MahSuperLibExceptionInterfce {}
Наследуются все стандартные исключения SPL c включением этого интерфейса
namespace Vendor\MahSuperLib\Exception;
use LogicException as SplLogicException;
class LogicException extends SplLogicException implements MahSuperLibExceptionInterface {}
Нестандартные исключения наследуются от созданных в предыдущем пункте
После этого любому обработчику достаточно ловить интерфейс, чтобы отловить только исключения только этой либы/проекта:
try {
// ...
} catch (MahSuperLibExceptionInterface $e) {
// hehe
}
И ссылка на довольно крутой, хоть и лаконичный пдф http://www.planetgeek.ch/wp-content/uploads/2014/11/Clean-Code-V2.4.pdf
И еще немного
Я не знаю как (у меня практически по минутам все расписано до конца января минимум), но в ближайшее время подниму себе стек jenkins + агенты на докере + selenium + phantom + sonarqube. Все предыдущее просто меркнет после того, как эта цепочка настроена. Jenkins позволит прогнать любые тесты приложения, а Sonarqube - это такой божественный сервер статанализа кода, который сам посчитыаеттехнический долг и выдаст, сколько его рефакторить. Проще один раз показать, посмотрите, это невероятное творение, умеет работать со всеми основными языками.
Пока что сижу на travis и codeship, планирую еще попробовать shippable. Ну и еще существует миллиард полезных сервисов (scrutinizer, versioneye, codeclimate), до которых просто руки не доходят.
простите за сумбурное изложение, позже может еще пару правок вкачу.