2.14 Структура проекта и репозитория
Обзор и мотивация
Структура проекта и репозитория это физическая организация кодовой базы: папки, файлы и соглашения об именовании, решающие, где что находится. Репозиторий (часто сокращаемый до «репо») это версионируемый контейнер, хранящий файлы проекта и их историю. Проект, иногда называемый решением, когда он группирует несколько связанных компонентов, это логическая единица программы, которую вы строите. Структура это карта, по которой вы находите, понимаете и меняете эту программу.
В небольшой команде один человек может держать всю раскладку в голове. В большой команде, с сотнями или тысячами инженеров, частыми переходами между командами и приходящими и уходящими подрядчиками, каждый иначе организованный репозиторий облагает новым когнитивным налогом. Открывая незнакомое репо, вы должны суметь угадать, где живут исходный код, тесты, документация и конфигурация развёртывания, не читая руководства. Когда каждое репо отвечает на эти вопросы одинаково, мобильность дёшева, а адаптация быстра. Когда каждое репо снежинка, каждое переключение контекста превращается в маленький исследовательский проект.
В корпоративной и государственной среде единая структура ещё и вопрос контроля и гарантий. Аудиторам, рецензентам безопасности и долгосрочным сопровождающим, часто работающим годы после ухода первоначальных авторов, нужно надёжно находить документы спецификаций, файлы лицензий, политики безопасности и определения сборки. Предсказуемая раскладка также позволяет автоматизированным инструментам (сканерам, анализаторам зависимостей, проверкам соответствия) одинаково работать по всему портфелю систем. Поэтому эта глава рассматривает структуру как соглашение, которое вы определяете один раз и применяете везде. Она тесно связана со стандартами кодирования и стилем (глава 2.1), контролем версий и управлением исходным кодом (глава 2.6) и документацией (глава 2.7).
Ключевые принципы
- Следуйте принципу наименьшего удивления: раскладка должна соответствовать ожиданиям опытного инженера, чтобы ничего не нужно было запоминать.
- Согласованность между репозиториями побеждает локальную хитрость; достаточно единообразная структура везде стоит больше идеальной структуры в одном месте.
- README это парадный вход; новичок должен ориентироваться по нему одному.
- Делайте структуру самоописывающей через именование, чтобы папки и файлы объявляли своё назначение.
- Обеспечивайте структуру заготовками и шаблонами, а не силой воли и комментариями на ревью.
- Разделяйте заботы физически: исходный код, тесты, документация, сборка и развёртывание принадлежат различным предсказуемым местам.
- Организуйте зависимости так, чтобы они шли в одну сторону, от стабильных ядер к изменчивым краям.
Рекомендации
Примите единообразную раскладку верхнего уровня
Определите стандартный набор папок верхнего уровня, которые использует каждый репозиторий там, где применимо, и задокументируйте, для чего каждая. Распространённое нейтральное к поставщикам соглашение включает: папку исходного кода (часто src) для эксплуатационного кода; папку тестов (часто test или tests) для автоматизированных тестов; папку docs для документации; папку build для определений сборки и результатов; папку deploy для развёртывания и инфраструктуры как кода (машиночитаемых определений серверов, сетей и сервисов, рассматриваемых в главе 8.2); папку scripts для автоматизации и инструментов разработчиков; папку examples для запускаемых образцов; и папку spec или specification для спецификаций требований и проекта. Не каждому репо нужна каждая папка, но там, где забота существует, она должна жить в ожидаемом месте с ожидаемым именем.
Сделайте README точкой входа
Требуйте файл README в корне репозитория как единую каноническую отправную точку. Он должен говорить, что это за проект, как его собрать и запустить, как запустить тесты, где найти более глубокую документацию, кто им владеет и как участвовать. README не весь набор документации; это указатель, ведущий к остальному (глава 2.7). Воспринимайте отсутствующий или устаревший README как дефект, потому что это первое, что прочтёт каждый новый инженер, аудитор или интегратор.
Стандартизируйте файлы редактора и конфигурации
Помещайте общую конфигурацию редактора и инструментов в репозиторий, чтобы каждый участник получал единообразное поведение автоматически. Файл .editorconfig (простой, независимый от редактора файл, определяющий правила пробелов, отступов и концов строк) удерживает базовое форматирование единым в разных редакторах и операционных системах. Добавьте файл игнорирования для системы контроля версий (чтобы результаты сборки и локальные артефакты никогда не коммитились) вместе с общими конфигурациями форматировщика и линтера, описанными в главе 2.1. Эти файлы делают соглашения репозитория действующими, а не просто задокументированными.
Определите соглашения об именовании и папках
Согласуйте соглашения об именовании папок и файлов (регистр, разделители, единственное или множественное число и обязательные суффиксы, например отмечающие тесты) и применяйте их единообразно. Имена должны раскрывать замысел и соответствовать словарю предметной области, используемому в остальной организации. Цель проста: путь должен передавать смысл, чтобы чтение имени папки или файла говорило, что внутри, не открывая.
Организуйте слои и зависимости намеренно
Структурируйте кодовую базу так, чтобы её архитектурные слои проявлялись в раскладке папок, а зависимости шли в одном разумном направлении. Политика высокого уровня не должна зависеть от низкоуровневых деталей. Общий стабильный код должен находиться там, где до него могут добраться многие модули, не создавая циклов. Когда вы делаете слоистость физической, отражённой в дереве каталогов, инженеры чаще её соблюдают, а нарушения легче заметить на ревью и в автоматических проверках зависимостей.
Обеспечивайте структуру заготовками и шаблонами
Предоставляйте заготовки (scaffolding), автоматическую генерацию стартового проекта, чтобы новые репозитории начинались уже правильными. Шаблон или cookiecutter (параметризованный скелет проекта, порождающий готовый репозиторий по ответам на несколько вопросов) кодирует стандартную раскладку, README, файлы конфигурации и настройку CI в одном месте. Когда инженеры создают новые сервисы из общего шаблона, согласованность становится умолчанием, а не стремлением, а улучшения шаблона доходят до будущих проектов.
Поддерживайте единообразие структуры по многим репозиториям в масштабе
Воспринимайте саму раскладку как управляемый стандарт: сопровождаемый централизованно, как любой другой инженерный стандарт (глава 1.7), и версионируемый как код (глава 2.6). Публикуйте её, предоставляйте шаблоны, её реализующие, и допускайте отклонения только через документированный процесс исключений, чтобы «стандарт» сохранял смысл. В масштабе портфеля почти вся ценность структуры происходит из её единообразия между репозиториями, поэтому дрейф главный риск, которым нужно управлять.
Пусть структура информирует выбор монорепозитория или нескольких репозиториев
Соотнесите структуру с решением о границе репозиториев из главы 2.6. Монорепозиторий (один репозиторий со многими проектами) нуждается в ясном внутреннем соглашении для разделения проектов и их общего кода, чтобы единое дерево оставалось навигируемым. Подход нескольких репозиториев (много малых репозиториев, по одному на проект или сервис) нуждается в сильной межрепозиторной согласованности, чтобы каждое репо казалось знакомым, хотя и стоит отдельно. В любом случае документированная, шаблонизированная структура то, что делает навигацию предсказуемой. Выбор границы меняет, где вы применяете соглашение, но не то, нужно ли оно.
Компромиссы: плюсы и минусы
| Выбор | Плюсы | Минусы |
|---|---|---|
| Строгая стандартная раскладка по всей организации | Мгновенная знакомость; переносимые инженеры; единообразные инструменты | Иногда плохо подходит необычным проектам; нужно управление |
| Свобода раскладки по командам | Локальная оптимизация; высокая автономия | Фрагментация; дорогое переключение контекста; несогласованные инструменты |
| Заготовки и шаблоны | Репозитории правильны по умолчанию; изменения распространяются | Сопровождение шаблонов; риск дрейфа сгенерированных репозиториев |
| Глубокая слоистая иерархия папок | Явная структура; ясные границы | Накладные расходы на навигацию; длинные пути; риск перепроектирования |
| Плоская неглубокая раскладка | Легко просматривать; мало церемоний | Плохое разделение; разваливается по мере роста проекта |
Доминирующий компромисс это единообразие против автономии. Единая стандартная раскладка убирает трение для многих инженеров, переходящих между кодовыми базами, ценой редкого проекта, потребности которого не вписываются в форму аккуратно. В большой организации коллективный выигрыш от знакомости почти всегда превышает эту локальную потерю. Поэтому рекомендуемая позиция сильный стандарт по умолчанию плюс документированный путь исключений (глава 1.7), а не жёсткое единообразие или неуправляемая свобода. Второстепенный компромисс глубина против простоты: достаточно структуры для разделения реальных забот, но не столько, чтобы навигация превращалась в поход по пустым папкам.
Вопросы для обсуждения с командой
Когда инженер переходит в незнакомое репо у нас, сколько времени ему нужно, чтобы найти тесты, конфигурацию развёртывания и владельца? Это налог на навигацию, который структура существует, чтобы устранить, и в масштабе портфеля он платится тысячи раз в год малыми порциями, складывающимися в серьёзную потерю инженерного времени. Смысл принципа наименьшего удивления в том, что опытный инженер должен суметь угадать, где живут исходный код, тесты, документация и развёртывание, не читая руководства, поэтому честная проверка в том, удаётся ли эта догадка по вашим репозиториям. Принесите на встречу реальное число: засеките, как долго вы ориентируетесь в двух-трёх незнакомых внутренних репозиториях, или возьмите данные адаптации о том, сколько новичкам нужно для первого изменения. Если ответ измеряется днями исследования, а не минутами узнавания, вы количественно оценили стоимость репозиториев-снежинок, и это оправдывает разовое вложение в стандартную раскладку, общую для каждого репо.
Проявляются ли наши архитектурные слои в дереве папок или циклы зависимостей прячутся внутри плоской раскладки? Структура не только о находимости: когда вы делаете слоистость физической, инженеры её соблюдают, а рецензенты и автоматические проверки зависимостей могут заметить нарушения, тогда как плоская куча позволяет неуместному сцеплению и циклам проникать незамеченными, пока изменение не станет опасным. В большой долгоживущей системе это то, что не даёт политике высокого уровня тихо зависеть от низкоуровневых деталей, и именно такую эрозию дёшево предотвратить и дорого расплетать. Принесите ваш граф зависимостей или проведите быструю проверку: есть ли циклы и зависит ли что-то стабильное от чего-то изменчивого? Ответ должен подтолкнуть вас отразить слои в каталогах и добавить автоматические проверки направления зависимостей, чтобы границы были видны в дереве и обеспечивались в конвейере, а не жили только в чьей-то ментальной модели.
Начинаются ли наши новые репозитории правильными из шаблона или мы полагаемся на страницу вики и добрые намерения? Структура, обеспечиваемая заготовками, умолчание; структура, описанная в документе, дрейфует, потому что реальность следует тому, что порождает репозитории, а не тому, что говорит страница о том, как они должны выглядеть. Для большой или регулируемой организации это ещё и вопрос гарантий: когда каждое репо порождено общим шаблоном, сканеры безопасности, анализаторы зависимостей и аудиторы каждый раз находят лицензию, политику безопасности, спецификацию и определение сборки в одном месте, через поставщиков и годы. Принесите свидетельства: сколько ваших недавних репозиториев были созданы из стандартного шаблона против собранных вручную и как далеко с тех пор дрейфовали шаблонизированные? Действие состоит в том, чтобы сделать шаблон единственным лёгким способом начать репо, управлять им как версионируемым стандартом с документированным путём исключений и обнаруживать дрейф автоматически, потому что именно в единообразии живёт почти вся ценность структуры.
Решили ли мы, охватывает ли наш стандарт монорепозиторий или много отдельных репозиториев, и действительно ли то же соглашение держится по обе стороны этой границы? Выбор границы репозиториев меняет, где вы применяете соглашение, но не то, нужно ли оно, и ошибка означает либо единое гигантское дерево, по которому никто не может ориентироваться, либо россыпь репозиториев, каждый из которых кажется чужим. Монорепозиторию нужно ясное внутреннее соглашение для разделения проектов и их общего кода, чтобы единое дерево оставалось навигируемым, тогда как подходу нескольких репозиториев нужна сильная межрепозиторная согласованность, чтобы каждое отдельное репо по-прежнему казалось знакомым. Принесите текущую опись: сколько у вас репозиториев, как разделён общий код внутри любого монорепозитория и замер времени, может ли инженер найти проект внутри большого дерева так же быстро, как в отдельном репо. Для большой корпорации или государственной программы, где разные поставщики поставляют отдельные репозитории, решите намеренно, какие части соглашения универсальны, а какие специфичны для границы, потому что аудиторам и платформенным инструментам нужно работать одинаково, приходит ли код одним деревом или пятьюдесятью.
Кто владеет нашим стандартом структуры и что на самом деле происходит, когда проект действительно не вписывается? В масштабе портфеля почти вся ценность структуры происходит из единообразия, поэтому настоящие риски это бесхозный стандарт, который гниёт, и путь исключений настолько расплывчатый, что каждая команда тихо изобретает свою раскладку. Напряжение между жёстким единообразием, не подходящим ни одному необычному проекту, и неуправляемой свободой, всё дробящей, а здоровый ответ это сильное умолчание плюс документированный проверяемый процесс исключений под управлением названного владельца и версионируемый как код. Принесите свидетельства: есть ли единый ответственный владелец, версионируемый документ стандарта с журналом изменений, журнал выданных исключений и причин и число недокументированных отклонений, которые вы можете найти на практике. В корпоративной и государственной среде исключение, которое никто не записал, пробел контроля, поэтому привязывайте каждое отклонение к письменному обоснованию и дате пересмотра и убедитесь, что контракты закупок, предписывающие раскладку, также называют, кто может одобрять отступления от неё.
Делают ли наши README и хранимые в репозитории файлы конфигурации наши соглашения действующими или они декоративны? README это парадный вход, а хранимые
.editorconfig, файл игнорирования и конфигурация линтера делают соглашения самообеспечиваемыми, однако это первое, что устаревает, и последнее, что кто-либо замечает, пока аудитор или новичок не может собрать проект. Напряжение между скромным README, остающимся актуальным, и подробным, который дрейфует, и между доверием к тому, что люди правильно форматируют код, и позволением общей конфигурации обеспечивать это автоматически. Принесите выборку: возьмите пять репозиториев и проверьте, сколько README действительно говорят, что это за проект, как его собрать, протестировать, запустить и кто им владеет, и сколько несут общие файлы конфигурации, а не полагаются на индивидуальные привычки. Для большой или регулируемой организации, где интеграторы, рецензенты безопасности и долгосрочные сопровождающие читают README прежде всего остального, воспринимайте отсутствующий или устаревший парадный вход как дефект с владельцем и проверяйте наличие файлов конфигурации автоматически, чтобы соответствие не зависело от доброй воли.
Взгляд по секторам
Стартап. Побеждает скорость, поэтому согласуйте одну простую достаточно плоскую раскладку для первого репо (src, test, docs, scripts, заполненный README, .editorconfig и файлы игнорирования) и сохраните её как лёгкий шаблон в тот же день. Сгенерируйте второй сервис из него, чтобы оба репо казались знакомыми, а новый подрядчик адаптировался за часы, а не занимался обратной разработкой снежинки. Сопротивляйтесь глубоким иерархиям и тяжёлому управлению, которые вам пока не нужны; вся отдача здесь в том, что два основателя и подрядчик делят одну карту.
Малый бизнес. Без платформенного специалиста и при ограниченном бюджете принимайте обычную раскладку, которую уже предполагают ваш язык или фреймворк, а не изобретайте свою, чтобы готовые инструменты и любой новый сотрудник приходили уже обученными ей. Покупайте заготовки (генератор фреймворка или шаблон cookiecutter), а не стройте свои, и тратьте скудные усилия на поддержание заполненного README в актуальном состоянии. Этот README самая дешёвая страховка на день, когда единственный человек, знавший раскладку, уйдёт.
Крупная организация. Между многими командами и сотнями репозиториев цель единообразие: публикуйте версионируемый стандарт структуры, генерируйте каждый новый сервис из общих шаблонов, обнаруживайте дрейф автоматически и допускайте отклонения только через документированный процесс исключений. Поскольку каждое репо выглядит одинаково, инженер, переведённый в новую команду, продуктивен за часы, а сканеры безопасности и зависимостей по всему портфелю каждый раз находят лицензию, политику безопасности и определение сборки в одном месте. Закладывайте сопровождение шаблонов и обнаружение дрейфа в бюджет явно, потому что именно эти затраты делают стандарт значимым в масштабе.
Государственный сектор. Закупки, прозрачность и долгосрочная подотчётность определяют раскладку, поэтому предписывайте общую структуру в стандартах поставки, связывающих каждого поставщика. Требуйте папку specification, связывающую код с утверждёнными требованиями, файлы лицензии и политики безопасности в корне и папку deploy с определениями инфраструктуры как кода, чтобы аудиторы находили артефакты соответствия одинаково в каждой системе. Поскольку подрядчики разных поставщиков следуют одной карте, сопровождение после окончания контракта стоит гораздо дешевле, а общество получает обоснованный проверяемый след от требования до работающего кода.
Примеры
Стартап. Стартап из трёх человек согласует простую стандартную раскладку для первого репо (src, test, docs, scripts, заполненный README, .editorconfig и файлы игнорирования) и сохраняет её как лёгкий шаблон. Когда месяц спустя они поднимают второй сервис, они генерируют его из этого шаблона, поэтому оба репо уже кажутся знакомыми, а новый подрядчик адаптируется за полдня. Они сопротивляются глубоким иерархиям папок, которые им пока не нужны, держа дерево достаточно плоским, чтобы охватить его одним взглядом. Стоимость составила один день настройки, и она избавляет от россыпи снежинок, которая иначе превратила бы каждое будущее репо в маленький исследовательский проект.
Крупная организация. Международный ритейлер ведёт сотни сервисов на нескольких языках. Его платформенная команда публикует версионируемый стандарт структуры репозитория и набор шаблонов проектов, его реализующих. Каждый новый сервис генерируется из шаблона, поэтому приходит со стандартными папками src, test, docs, deploy и scripts, заполненным README, .editorconfig, файлами игнорирования и работающим конвейером CI. Поскольку каждый репозиторий выглядит одинаково, инженер, переведённый в новую команду, продуктивен за часы, а сканеры безопасности и зависимостей по всей организации работают единообразно, потому что всегда находят файлы там, где ожидают.
Государственный сектор. Национальное агентство, модернизирующее унаследованные системы, предписывает общую раскладку репозитория как часть стандартов поставки для всех поставщиков. Каждый репозиторий должен содержать папку specification, связывающую код с утверждёнными требованиями, документированный README, файлы лицензии и политики безопасности в корне и папку deploy с определениями инфраструктуры как кода (глава 8.2). Поскольку подрядчики разных поставщиков следуют одной структуре, аудиторы агентства могут находить артефакты соответствия одинаково в каждой системе, а долгосрочное сопровождение после окончания контракта стоит гораздо дешевле, потому что приходящие сопровождающие уже знают карту.
Бизнес-обоснование: мотивы, ROI и TCO
Стоимость принятия стандарта структуры в основном разовая: согласование раскладки, построение шаблонов и документирование соглашения. Повторяющаяся стоимость низкая, сосредоточена в сопровождении шаблонов и управлении исключениями. Стоимость отсутствия стандарта повторяющаяся и нарастающая: каждый инженер, открывающий незнакомое репо, платит налог на навигацию, каждая адаптация идёт медленнее, а автоматическим инструментам приходится настраиваться на каждое репо, потому что ничто не лежит там, где ожидается. По большой организации эти мелкие трения умножаются в серьёзные потери инженерного времени.
Отдача проявляется как более быстрая адаптация, более дешёвая мобильность между командами, более высокий сигнал от инструментов всего портфеля и, в регулируемой среде, более низкая стоимость аудита и долгосрочного сопровождения, потому что артефакты всегда находимы. Совокупная стоимость владения (TCO, то есть полная стоимость жизненного цикла создания, эксплуатации и сопровождения системы) падает сильнее всего в долгоживущих системах, где сопровождающие, выигрывающие от предсказуемой структуры, обычно не те авторы, что её создали. Чтобы обосновать руководству, подавайте структуру как дешёвый стандарт большого рычага, улучшающий продуктивность разработчиков и готовность к аудиту, и назовите число текущей стоимости несогласованности по данным о времени адаптации и усилиям на поиск вещей в незнакомых репозиториях.
Антипаттерны и ловушки
- Репозиторий-снежинка: каждое репо организовано иначе, поэтому каждое приходится изучать с нуля.
- Отсутствующий или устаревший README: нет парадного входа, и новички вынуждены восстанавливать, как собрать и запустить проект, обратной разработкой.
- Структура документом, а не шаблоном: страница вики описывает стандартную раскладку, но ничто её не порождает и не обеспечивает, поэтому реальность дрейфует от неё.
- Дрейф шаблона: репозитории, порождённые из шаблона, со временем расходятся, а улучшения шаблона никогда до них не доходят.
- Перепроектированная иерархия: глубокие гнёзда почти пустых папок, добавляющие церемонию без помощи в навигации.
- Смешанные заботы: исходный код, тесты, результаты сборки и секреты свалены вместе без чёткого разделения.
- Коммит результатов сборки и локальных артефактов: сгенерированные файлы в репозитории, потому что правила игнорирования не настроены, загрязняющие историю и diff.
- Нарушения слоёв, скрытые плоской структурой: нет физических границ, поэтому циклы зависимостей и неуместное сцепление проникают незамеченными.
Модель зрелости
- Уровень 1 (Начальный): Каждый репозиторий организован стихийно его авторами в ответ на то, что нужно в данный момент; раскладки сильно различаются; README отсутствуют или ненадёжны; новичков приходится проводить по каждому репо вручную.
- Уровень 2 (Развитие): Базовые соглашения существуют неформально, и многие репо похожи друг на друга; некоторые команды ведут собственную стартовую раскладку; но нет авторитетного стандарта, общих заготовок, а структура заметно дрейфует от команды к команде.
- Уровень 3 (Стандартизация): Документированный версионируемый стандарт структуры соблюдается по организации; новые репозитории порождаются из общих шаблонов, несущих стандартную раскладку, README, файлы конфигурации и CI; отклонения проходят через документированный процесс исключений, а не происходят молча.
- Уровень 4 (Управление): Соответствие стандарту измеряется и контролируется данными: автоматические проверки сообщают, какая доля репо соответствует раскладке, как далеко дрейфовали шаблонизированные репо, полноту README и нарушения направления зависимостей, всё отслеживается относительно базовых значений; измеряется время адаптации и навигации; исключения журналируются и пересматриваются, а изменения шаблона утверждаются на основании свидетельств, а не мнения.
- Уровень 5 (Оркестрация): Структура непрерывно улучшается и адаптивна: улучшения шаблона автоматически распространяются на существующие репозитории, управление структурой интегрировано с инструментами безопасности, соответствия и платформы, а стандарт намеренно эволюционирует по мере смещения языков, архитектур и портфеля, сохраняя высокое единообразие, пока организация меняется вокруг него.
Идеи для обсуждения
- Какие папки верхнего уровня должны быть по-настоящему универсальными по вашей организации, а какие необязательными?
- Как не дать репозиториям, порождённым из шаблона, со временем дрейфовать от него?
- Где проходит граница между полезной слоистой иерархией и перепроектированной церемонией папок?
- Чем должен отличаться ваш стандарт структуры, если вообще, между монорепозиторием и подходом нескольких репозиториев?
- Каков правильный процесс исключений для проекта, чьи подлинные потребности не вписываются в стандартную раскладку?
- Какую часть вашей структуры можно проверять автоматически и что по-прежнему опирается на человеческое ревью?
- Кто владеет стандартом структуры и его шаблонами и как изменения предлагаются и внедряются?
Главные выводы
- Организуйте каждый репозиторий так, чтобы любой инженер мог ориентироваться в любой кодовой базе по ожиданию, следуя принципу наименьшего удивления.
- Примите единообразную раскладку верхнего уровня (исходный код, тесты, документация, сборка, развёртывание, скрипты, примеры, спецификация) и сделайте README точкой входа.
- Храните конфигурацию редактора и инструментов (например,
.editorconfig) в репозитории, чтобы соглашения были действующими, а не просто записанными. - Обеспечивайте структуру заготовками и шаблонами, чтобы новые репозитории были правильными по умолчанию.
- В масштабе ценность в единообразии: управляйте стандартом, контролируйте дрейф и допускайте отклонения только по документированному исключению.
Источники и дополнительное чтение
- Robert C. Martin, Clean Architecture: A Craftsman’s Guide to Software Structure and Design
- Steve McConnell, Code Complete: A Practical Handbook of Software Construction
- Andrew Hunt and David Thomas, The Pragmatic Programmer
- Titus Winters, Tom Manshreck, and Hyrum Wright (eds.), Software Engineering at Google
- Scott Chacon and Ben Straub, Pro Git
- EditorConfig project documentation (as a reference standard for editor configuration)