Skip to content

Instantly share code, notes, and snippets.

@benbor
Last active June 27, 2019 17:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benbor/465c27c618153f732173eb7d6a6cfddf to your computer and use it in GitHub Desktop.
Save benbor/465c27c618153f732173eb7d6a6cfddf to your computer and use it in GitHub Desktop.

Бизнесс

Есть несколько корпоративных приложений. Каждое из приложений написано на на PHP7 в своем стиле, в своих изолированных репозиториях, за преложения ответсвенны разные разработчики. Каждое приложение имеет своих пользователей. Любой пользователь может подключить различные виды связи с ним. Есть некие процессы в приложении, после которых нужно уведомить пользователя по всем зарегистрированным каналам связи.

Пример #1

В приложении A можно ввести только свой электронный адрес и номер телефона. Пользователь Bob ввел в систему свой электронный адрес bob@example.com и свой номер телефона +375555555555. После логина Bob в систему, приложение посылает сообщение "Hi" пользователю Bob на Email и SMS.

Пример #2

В приложении B можно войти с помощью социальных сетей, email, мобильного номера телефона. Пользователь Alice зашла с мобильного iOS, разрешила Push уведомления (приложению доступен APNS token) и ввела свой email. Для Alice строка "Hello" должна быть доставлена через Push уведомление на ее мобильный телеофн и в сообщении на электронную почту.

Постановка задачи

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

Этой библиотекой будут пользоваться другие разработчики. Разработчики будут ее подключать (копировать исходники или устанавливать через composer), настраивать (через контейнер зависимости или непосредственно по месту использования) и рассылать строку.

Библиотека должна позволять любому приложению добавить свою реализацию транспорта. Релазиция низкоуровнего транспорта в этом ТЗ нам не интересна. Договоримся, что низкоуровневый транспорт всегда выполняется (не нужна обработка ошибок) и выглядит так:

function emailNativeSend(string $message, string $emailAddress, string $smtpUrl, string $smtpUser, string $smptPassword): void;
function smsNativeSend(string $message, string $phoneNumber, string $serviceSecret): void;
function apnsPushNativeSend(string $message, int $deviceId, string $apnsUrl, string $apnsSecretKey): void;
function gsmPushNativeSend(string $message, int $deviceId, string $gsmUrl, string $gsmSecretKey): void;
//etc

Использование библиотеки должно быть максимально простым и принимать только два аргумента - идентификатор пользователя и сообщение для передачи.

Требования

  • PHP 7.1+, phpunit
  • Продуманная OOP архитектура по принципам GRASP, SOLID, DDD
  • Минимум один unit тест на логику библиотеки
  • Минимум два транспорта в стандартной поставке библиотеки
  • Библиотека должна иметь возможность расширять доступные транспорты
  • Предоставить пример (Readme.md - можно на русском) как библиотеку настраивать и использовать

Пример

Рассмотрим пример, где наc, в принципе, устраиват функциональность (не хватае расширяемости со стороны приложения) но категорически (warning) не устраивает все остальное:

<?php
// библиотека
 
class TheSender
{
    public static $isEmailAvailable = false;
    public static $smtpAddress = "";
    public static $smtpUser = "";
    public static $smtpPassword = "";
 
    public static $isSmsAvailable = false;
    public static $smsSecretKey = "";
     
    public static $knownUsers = [];
 
    public function send(string $id, string $message)
    {
        if (isset(static::$knownUsers[$id]['email']) && static::$isEmailAvailable) {
            emailNativeSend(
                $message,
                static::$knownUsers[$id]['email'],
                static::$smtpAddress,
                static::$smtpUser,
                static::$smtpPassword
            );
        }
 
        if (isset(static::$knownUsers[$id]['smsNumber']) && static::$isSmsAvailable) {
            smsNativeSend($message, static::$knownUsers[$id]['smsNumber'], static::$smsSecretKey);
        }
    }
}
 
// настройка
TheSender::$isEmailAvailable = true;
TheSender::$smtpAddress = 'smtp.example.com';
TheSender::$smtpUser = 'login';
TheSender::$smtpPassword = 'password';
 
 
// использование
TheSender::$knownUsers[] = [
    $user->getId() => [
        'email' => $user->getEmail(),
        'smsNumber' => $user->getPhone(),
    ],
];
 
TheSender::send($user->getId, 'Hi!');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment