Модульность, как писал Рауф, несет в себе множество преимуществ. Давайте рассмотрим «правильную» модульность в контексте разработки программ. В примерах я специально мешал языки человеческие и программистские, дабы не привязываться к реализации языков программирования, а дать возможность читателю подумать — как такое лучше реализовать в его языке. Во преки тому, что я и сам сторонник максимальной гибкости и модульности, в статье я покажу, что даже здесь может быть перебор. Выбор в любом случае остается за разработчиком. И разработчик несет очень большую ответственность за этот выбор. Что выбрать? Сделать монолит, и через пару лет убиться на его поддержке, или сделать максимально гибко и потратить деньги работодателя на абстракции, которые никогда не пригодятся?
Модульность дает нам свободу повторного использования кода. Как именно, пожалуй стоит рассмотреть на примере. Приложение должно уметь войти на определенный FTP-сервер и забрать обновление внутренних данных (карт, списка товаров, БД адресов и т.п.).
Первый пример:
в коде приложения расставляем инструкции сдедующего содержания: соединиться, передать пароль, перейти в папку, забрать файл. Все предельно просто и понятно.
Пример второй, несколько сложнее:
Создаем отдельный класс, которому передадим, хост, порт, пароль и путь до файла. Использовать класс будем примерно так:
Здесь несколько усложняется код внутри класса, но несколько упрощается его использование, не так ли?
Пример третий, еще более сложный:
создадим класс соединения, который будем использовать так:
Конфигурация для разных соединений может быть разная. Примеры:
или
Похоже третий пример уже должен срывать крышу у новичков, ведь тут придется реализовывать драйвер для каждого протокола, зато мы в любой момент можем добавить драйер на новый протокол, например webdav, ssh, zeroconf, smb и т.д., что позволит нам обойтись минимальными изменениями в клиентском коде.
Если же пойти в сторону еще большей гибкости и делить подмодули на под-под-подмодули получается следующее:
Пока меня не понесло на еще большую гибкость, от которой можно потерять крышу надолго, думаю стоит подвести итоги.
В последнем примере мы имеем почти максимальную гибкость (или модульность), которую мы можем использовать практически в любом контексте приложения, если идет речь о сохранении файла из сети, однако первый пример гораздо более прост и быстр в реализации. В итоге все зависит от ваших задач. Если вы создаете универсальную библиотеку, то можно обвернуть и локальную файловую систему (drv=LocaFileSystem), но если в вашем небольшом приложении нужно просто обновить данные, тогда вполне подойдет и первый пример.
Вывод: серебрянной пули не существует, а значит придется искать золотую середину.
Модульность дает нам свободу повторного использования кода. Как именно, пожалуй стоит рассмотреть на примере. Приложение должно уметь войти на определенный FTP-сервер и забрать обновление внутренних данных (карт, списка товаров, БД адресов и т.п.).
Первый пример:
в коде приложения расставляем инструкции сдедующего содержания: соединиться, передать пароль, перейти в папку, забрать файл. Все предельно просто и понятно.
Пример второй, несколько сложнее:
Создаем отдельный класс, которому передадим, хост, порт, пароль и путь до файла. Использовать класс будем примерно так:
записать_в_файл(локальный_путь, новое_соединение(хост, порт, пароль, путь).закачать())
Здесь несколько усложняется код внутри класса, но несколько упрощается его использование, не так ли?
Пример третий, еще более сложный:
создадим класс соединения, который будем использовать так:
Соединение({конфигурация})
Конфигурация для разных соединений может быть разная. Примеры:
{protocol: ftp, port: 224, user: vasia, password: secret}
или
[proto->http; domain->example.com; file->foo/bar/1.zip]
Похоже третий пример уже должен срывать крышу у новичков, ведь тут придется реализовывать драйвер для каждого протокола, зато мы в любой момент можем добавить драйер на новый протокол, например webdav, ssh, zeroconf, smb и т.д., что позволит нам обойтись минимальными изменениями в клиентском коде.
Если же пойти в сторону еще большей гибкости и делить подмодули на под-под-подмодули получается следующее:
c = Connector;
drv = SMTPDriver;
auth = Authenticator;
auth->setCrypt('sha1');
auth->setUser(Application->getCurrentUser());
drv->setAuth(auth);
c->setDriver(drv);
c->connect()->authenticate() OR throw Error;
path = smtpPathDriver('letter:459;attachmend-cid:file.zip');
writeFile('local/path/to/file.zip',c->getFile(path));
Пока меня не понесло на еще большую гибкость, от которой можно потерять крышу надолго, думаю стоит подвести итоги.
В последнем примере мы имеем почти максимальную гибкость (или модульность), которую мы можем использовать практически в любом контексте приложения, если идет речь о сохранении файла из сети, однако первый пример гораздо более прост и быстр в реализации. В итоге все зависит от ваших задач. Если вы создаете универсальную библиотеку, то можно обвернуть и локальную файловую систему (drv=LocaFileSystem), но если в вашем небольшом приложении нужно просто обновить данные, тогда вполне подойдет и первый пример.
Вывод: серебрянной пули не существует, а значит придется искать золотую середину.