«Разработка ПО — это Искусство Компромисса», wiki.c2.com
Я видел множество проектов, выросших из простой «MVC» структуры. Часто разработчики объясняют шаблон MVC так: «View (представление) — это HTML-шаблоны, Model (модель) — это класс Active Record (например, Eloquent) и один контроллер, чтобы править всеми!». Хорошо, не один, но обычно вся дополнительная логика реализуется в классах-контроллерах. Контроллеры часто содержат огромное количество кода, реализующего разную логику (загрузку картинок, вызовы внешних API, работу с базой, и т.д.). Иногда некоторая логика выносится в «базовые» контроллеры, просто чтобы уменьшить количество дублированного кода. Одни и те же проблемы возникают как в средних проектах, так и в огромных порталах с миллионами посетителей в день.
Шаблон MVC был изобретен в 1970-х годах для графического интерфейса пользователя (GUI). Простые CRUD (Create, Read, Update and Delete) веб-приложения, в сущности, являются просто интерфейсом к базе данных, поэтому пере-изобретённый шаблон «MVC для веб» стал очень популярен. Однако, веб-приложения очень быстро перестают быть только лишь интерфейсом к базе данных. Что говорит шаблон MVC про работу с файлами (изображения, музыка, видео), внешними API, кэшэм? Что если у сущностей поведение отличается от простого Создать-Изменить-Удалить? Ответ простой: Модель в терминах MVC — это не только класс Active Record. Она содержит всю логику работы с данными приложения. Больше 90% кода современного сложного веб-приложения — это Модель. Создатель фреймворка Symfony Fabien Potencier как-то написал: «Я не люблю MVC, потому что это не то, как работает веб. Symfony2 — это HTTP фреймворк; это Request/Response фреймворк» Я могу сказать то же самое про Laravel и многие другие фреймворки.
Фреймворки, такие как Laravel, содержат кучу RAD-возможностей, которые позволяют разрабатывать приложения очень быстро, срезая некоторые углы. Они весьма полезны на стадии приложения «интерфейс для работы с базой данных», но часто становятся источником боли по мере развития. Я делал много рефакторингов просто, чтобы избавить приложения от таких возможностей. Вся эта авто-магия и «удобные» валидации в стиле «быстро сходить в базу данных и проверить нет ли такого email в таблице» хороши, но разработчик должен полностью понимать как они работают и когда лучше от них отказаться.
С другой стороны, советы от крутых разработчиков в стиле «ваш код на 100% должен быть покрыт юнит-тестами», «не используйте статические методы» и «зависеть нужно только от абстракций» быстро становятся своеобразными карго-культами для некоторых проектов. Слепое следование им приводит к огромным потерям во времени. Я видел интерфейс IUser с более чем 50 свойствами (полями) и класс User: IUser со всеми этими свойствами скопированными туда (это был C# проект). Я видел огромное количество абстракций просто для того, чтобы достичь требуемого процента покрытия юнит-тестами. Некоторые эти советы могут быть неверно истолкованы, некоторые применимы только в конкретной ситуации, некоторые имеют важные исключения. Разработчик должен понимать какую проблему решает шаблон или совет и при каких условиях он применим.
Проекты бывают разные. К некоторым хорошо придутся определённые шаблоны и практики. Для других они будут излишни. Один умный человек сказал: «Разработка ПО — это всегда компромисс между краткосрочной и долгосрочной продуктивностью». Если мне нужен один функционал в другом месте проекта, то я могу скопировать его туда. Это будет очень продуктивно, но начнет очень быстро доставлять проблемы. Почти каждое решение про рефакторинг или применение какого-либо шаблона представляет собой ту же дилемму. Иногда, решение не применять шаблон, который сделает код «лучше» будет более правильным, поскольку полезный эффект от него будет меньше, чем время затраченное на его реализацию. Балансирование между шаблонами, практиками, техниками, технологиями и выбор наиболее подходящей комбинации для конкретного проекта является наиболее важным умением разработчика/архитектора.
В этой книге я покажу наиболее частые проблемы, возникающие в процессе роста проекта и как разработчики обычно решают их. Причины и условия данных решений весьма важная часть книги. Я не хочу создавать новые карго-культы.
Я должен предупредить:
- Эта книга не для начинающих. Чтобы понимать описываемые проблемы вы должны поучаствовать хотя бы в одном проекте. В одиночку или в команде.
- Эта книга не пособие. Много шаблонов будут описаны поверхностно, с целью просто познакомить читателя с ними. Несколько полезных ссылок вас ожидает в конце книги.
- Примеры этой книги никогда не будут идеальными. Я могу назвать какой-то код «корректным» и найти кучу ошибок в нем в следующей главе.