Дизайн API в С++

В этом году на C++ Russia я рассказывал про API дизайн. Эта статья — пересказ и переосмысление моего доклада.

То, что я здесь расскажу, основано на моем личном опыте — про API дизайн я думаю уже лет 15, с того момента как в 2008 м начал читать ревью библиотек на входе в boost (кстати, всем рекомендую).

В первой части я сфокусируюсь на базовых вещах, которые применимы практически к любому императивному языку программирования, не только к C++. Будет также часть 2, более приближенная собственно к C++, в которой я расскажу о некоторых фичах языка и стандартной библиотеки, которые помогут вам сделать ваши API еще лучше.

Программная Архитектура

Сначала поговорим об архитектуре. В современных инженерных кругах каждый раз когда кто-то говорит слово «Архитектура,» многие сразу думают о System Design собеседованиях в крупные зарубежные компании — как из кафки, редиса и PostgreSQL собрать сервис, который будет json’ы перекладывать.

Мы сегодня будем говорить об архитектуре на более низком уровне — об архитектуре на уровне отдельной программы или сервиса.

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

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

Если вы оказались в такой ситуации — вам пора задуматься об архитектуре вашего ПО.

Архитектура — это вид с высоты птичьего полета. Например, если вы пишете графический редактор, то вам наверняка придется написать код сохранения и загрузки разных форматов изображений, код инструментов, которые будут доступны пользователю, реализацию undo/redo, код различных фильтров, и т.п. Архитектура — это про то, как весь этот код связать в единое целое так, чтобы получилось достаточно гибкое решение.

Чем архитектура, о которой вовремя подумали, отличается от архитектуры, которая сама как-то зародилась, как жизнь в кастрюле с макаронами которую вы забыли на балконе? Что вообще такое «хорошая архитектура?» Мне нравится тейк автора Game Programming Patterns:

What is good software architecture?

For me, good design means that when I make a change, it«s as if the entire program was crafted in anticipation of it. I can solve a task with just a few choice function calls that slot in perfectly, leaving not the slightest ripple on the placid surface of the code.

That sounds pretty, but it«s not exactly actionable. «Just write your code so that changes don«t disturb its placid surface.» Right.

Let me break that down a bit. The first key piece is that architecture is about change. Someone has to be modifying the codebase. If no one is touching the code — whether because it«s perfect and complete or so wretched no one will sully their text editor with it — its design is irrelevant. The measure of a design is how easily it accommodates changes. With no changes, it«s a runner who never leaves the starting line.

За мыслью о легкости изменений на самом деле лежит довольно много:

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

  • Хорошая архитектура помогает с локальностью изменений. У вас бывало такое, что чтобы реализовать какую-то новую фичу нужно воткнуть десяток-другой if’ов по всей кодовой базе? Это пример нелокальности изменений.

  • Хорошая архитектура помогает не сажать баги.

  • Если вы все-таки посадили баг, то хорошая архитектура помогает быстро его найти.

  • Хорошая архитектура находит баланс между гибкостью и простотой. Вы наверняка участвовали в проектах, в которых разработчики увлеклись и наархитектурили — такое бывает когда продуктовые требования не ясны, и инженеры стараются предусмотреть все возможные пути дальнейшего развития продукта, и в итоге за архитектурностью теряется суть происходящего.

  • Хорошая архитектура помогает быстрее решать возникающие бизнес-задачи, реализовывать новые фичи, ускорять тормозные участки.

И самое главное — хорошая архитектура отвечает внешним требованиям. Это в частности означает, что если вы пишете прототип, то ничего из того что я здесь написал вам не нужно — вам нужно за минимальное время собрать что-то рабочее. Возможно после этого вы этот прототип просто выкинете.

На мой взгляд, об архитектуре нужно задумываться если:

  • Вы пишете код, который будет долго жить и широко использоваться.

  • Вы пишете библиотечный код.

  • Вы любите неконтролируемо архитектурить и хотите научиться делать это контролируемо.

Вопрос инвестирования усилий разработчиков в хорошую архитектуру — это на самом деле вопрос того, вернутся ли эти инвестиции. Оценить это без большого опыта в разработке бывает сложно, особенно если обе рассматриваемых альтернативы (инвестировать vs не инвестировать) покрыты для вас мраком, и конкретные шаги вам не ясны. Решить не инвестировать время в архитектуру потому что в данный момент этого не требуется, и не инвестировать в архитектуру потому что вы не понимаете, как и зачем — это две очень разные ситуации, которые при этом для стороннего наблюдателя могут выглядеть абсолютно одинаково. Вот только в первой ситуации решение приняли вы, а во второй ситуации решение случилось само. В этой статье я постараюсь частично развеять мрак, чтобы вы лучше понимали, какие шаги нужно предпринять, чтобы сделать ваш код лучше, и чаще оказывались в ситуации, когда вы можете принять осведомленное решение — архитектурить, или и так сойдет.

© Habrahabr.ru