Начнем с цитаты Сэнди Мец из ее прекрасного поста о почему мы спорим о стиле:

Я твердо верю, что весь код, который я лично должен изучить, должен поступать ко мне в согласованном формате. Код читается гораздо чаще, чем пишется, а это означает, что окончательная цена кода заключается в его чтении. Из этого следует, что код должен быть оптимизирован для удобства чтения, что, в свою очередь, диктует, что весь код приложения должен следовать одному и тому же стилю. Придерживаясь единого стиля, вы экономите деньги.

Spatie - веб-агентство. Поэтому большую часть времени мы работаем над несколькими проектами одновременно. Когда первоначальный проект будет завершен, мы будем поддерживать его в течение нескольких лет. Чтобы вещи оставались управляемыми, мы стараемся кодировать вещи последовательным образом. Таким образом, мы можем погрузиться в проект и легко его рассуждать. Я утверждаю, что помимо соблюдения единого стиля кода, последовательная настройка проектов также сэкономит время и деньги.

В течение многих лет я был единственным разработчиком в Spatie. Казалось бы, было легко поддерживать последовательность, потому что над кодом больше никто не работал. Но правда в том, что в то время я, конечно, не заметил небольших различий в моем стиле кода в разных проектах (тогда PSR-2 еще не применялась). Теперь, когда компания растет (Алекс недавно присоединился к нашей команде с новыми членами на подходе), становится все более важным сохранять последовательность.

Как и Сэнди, упомянутый в приведенной выше цитате, код следует оптимизировать для удобства чтения. Если весь код выполнен в едином стиле, вы сэкономите деньги, потому что понимание кода займет меньше времени. Но я бы сказал, что наличие руководства по стилю также сэкономит вам время на написание кода. Пытаетесь решить, должны ли названия видов или названия маршрутов быть верблюжьими или шашлычными? Не тратьте время зря и просто ознакомьтесь с соответствующими рекомендациями.

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

За ширмами

Сам сайт руководств построен на Laravel. Это полностью открытый исходный код. Вот репозиторий, содержащий код, который фактически развернут на нашем сервере.

Мы создали сайт с рекомендациями таким образом, чтобы каждый мог внести свой вклад. Внизу каждой страницы есть Edit this page on GitHub ссылка. Нажатие на нее создаст PR против репо. Когда мы объединяем PR, код будет автоматически развернут (для этого мы используем функцию автоматического развертывания Forge).

Поскольку рекомендации - это наши очень упрямые мысли о том, как что-то делать, мы не собираемся просто соглашаться с каждым полученным пиаром. Вы не можете изменить наше мнение, просто придумав новое правило. Но мы приветствуем новые правила, с которыми мы согласны, или обсуждение того, почему наши существующие правила могут быть плохими. И, конечно, мы также благодарны за PR, которые исправляют опечатки.

Хранение контента

Сам контент хранится в виде набора файлов уценки. Для отображения каждой страницы (кроме домашней) используется PageController:

namespace App\Http\Controllers;

use App\Markdown\MarkdownConverter;

class PageController extends Controller
{
    public function __invoke($url)
    {
        abort_unless($page = app('navigation')->getPage($url), 404);

        return view('page', [
            'title' => $page->title,
            'editUrl' => $page->edit_url,
            'contents' => MarkdownConverter::convert($page->contents),
        ]);
    }
}

Сделать контент приватным

Вышеупомянутый PageController контроллер спросит Navigation класс, какая страница должна отображаться. Взглянув на код класса Navigation, вы заметите, что он также пытается получить контент из частного каталога. Этот частный каталог содержит контент, который мы не хотим публиковать публично, например, полусекретную информацию и настраиваемые процедуры, которые не представляют интереса для внешнего мира.

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

Вход в систему

В Spatie мы используем Google Apps, и у каждого члена команды есть собственный адрес электронной почты в домене spatie.be. Было бы неплохо, если бы кто-нибудь с spatie.be адресом в Google мог войти в систему? Тогда нам не нужно было бы вручную создавать учетные данные всякий раз, когда мы принимаем нового члена команды.

Вот почему мы решили использовать Laravel Socialite для обработки логинов. Socialite позволяет очень легко аутентифицироваться с поставщиками OAuth, такими как Google, Facebook, Github,… Установить Socialite очень просто. После того, как он будет установлен и настроен в Google, вам не потребуется слишком много кода для обработки входа в социальные сети.

Это весь LoginController:

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\User;
use Socialite;

class LoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function redirectToProvider()
    {
        return Socialite::driver('google')
            ->scopes(['email'])
            ->redirect();
    }

    public function handleProviderCallback()
    {
        $user = Socialite::driver('google')->stateless()->user();

        abort_unless(ends_with($user->getEmail(), '@spatie.be'), 403);

        $authenticatableUser = User::findOrCreate($user);

        auth()->login($authenticatableUser, true);

        return redirect('/');
    }

    public function logout()
    {
        auth()->logout();

        return redirect('/');
    }
}

При посещении /login приложение выполнит метод redirectToProvider. Пользователь будет перенаправлен на страницу входа в Google. Когда пользователи предоставят правильные учетные данные, Google перенаправит их обратно на наш сайт. Этот ответ от Google обрабатывается в handleProviderCallback. Здесь мы прерываем работу, если адрес электронной почты вошедшего в систему пользователя не заканчивается на @spatie.be. А еще есть кусок скучного кода. Поскольку социальный пользователь не может быть аутентифицирован напрямую, мы находим (или создаем) обычного пользователя в базе данных и регистрируем его.

В заключение

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

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

Созданием сайта и написанием инструкций в значительной степени руководил мой коллега Себастьян, который, как всегда, проделал отличную работу.

Этот сайт - не первое, что мы открыли в исходном коде. Взгляните на страницы с открытым исходным кодом на сайте нашей компании, чтобы узнать о ранее созданных нами пакетах Laravel, PHP и JavaScript.