Розв'язка
Це в кінцевому рахунку про розв’язку для мене в кінці дня на самому фундаментальному рівні дизайну, позбавленому нюансу характеристик наших компіляторів і лінкерів. Я маю на увазі, що ви можете робити такі речі, як зробити так, щоб кожен заголовок визначав лише один клас, використовувати pimpls, пересилати декларації на типи, які потрібно лише оголосити, не визначити, можливо, навіть використовувати заголовки, які містять лише прямі декларації (наприклад:) <iosfwd>
, один заголовок на вихідний файл , систематизувати систему послідовно на основі типу речі, яка оголошується / визначається тощо.
Методи зменшення "залежностей від компіляції від часу"
І деякі з цих методів можуть допомогти трохи, але ви можете вичерпати ці практики та все ж знайти свій середній вихідний файл у вашій системі потребує двосторінкової преамбули #include
директиви робити що-небудь трохи осмислене в часи збірки з високою швидкістю, якщо ви зосереджуєтесь на тому, щоб зменшити залежність часу компіляції на рівні заголовка, не зменшуючи логічних залежностей в дизайні інтерфейсу, і хоча це не може вважатися "заголовками спагетті" строго кажучи, я Ще сказати, це означає подібні згубні питання, як продуктивність на практиці. Зрештою, якщо вашим підрозділам компіляції все-таки потрібен набір інформації, щоб було видно, щоб зробити що-небудь, то це буде перекладено на збільшення часу збірки та примноження причин, по яких ви потенційно можете повернутися назад і змінити речі, роблячи розробників. відчуваю, що вони головують над системою, просто намагаються завершити щоденне кодування. Це '
Наприклад, ви можете змусити кожну підсистему надати один дуже абстрактний файл заголовка та інтерфейс. Але якщо підсистеми не відокремлюються одна від одної, то ви отримуєте щось, що нагадує спагетті знову з інтерфейсами підсистеми залежно від інших інтерфейсів підсистеми з графіком залежності, який схожий на безлад для того, щоб працювати.
Передача декларацій до зовнішніх типів
З усіх методів я виснажився, щоб спробувати отримати колишню базу коду, яка займала дві години, а розробники інколи чекали 2 дні на свою чергу в CI на наших серверах побудови (ви майже можете уявити, що ці верстати будують як виснажені звірі з тягаря, несамовито намагаючись щоб не відставати, поки розробники не змінюють свої зміни), для мене найбільш сумнівними були типи оголошення вперед, визначені в інших заголовках. І мені вдалося зменшити цю кодову базу до 40 хвилин або близько того після віку, роблячи це невеликими поступовими кроками, намагаючись зменшити "заголовки спагетті", найбільш сумнівної практики заднього огляду (як змусити мене втратити з уваги фундаментальний характер конструкція, коли тунель бачив взаємозалежності заголовків), оголошував типи вперед, визначені в інших заголовках.
Якщо ви уявляєте Foo.hpp
заголовок, який має щось на кшталт:
#include "Bar.hpp"
І він використовує лише Bar
в заголовку спосіб, який вимагає його оголошення, а не визначення. тоді може здатися, що ніхто не забуде декларувати, class Bar;
щоб уникнути того, щоб визначення було Bar
видимим у заголовку. За винятком того, що на практиці часто ви знайдете більшість компіляційних одиниць, які Foo.hpp
все ще використовують, і все-таки потрібно Bar
визначити їх додатковим тягарем, коли потрібно включити Bar.hpp
себе Foo.hpp
, або ви натрапите на інший сценарій, коли це справді допомагає. % ваших підрозділів компіляції можуть працювати без включення Bar.hpp
, за винятком випадків, коли вони ставлять більш фундаментальне дизайнерське питання (або, принаймні, я думаю, що це повинно сьогодні), чому їм потрібно навіть бачити декларацію Bar
і чомуFoo
навіть потрібно турбуватися про це, якщо це не має значення для більшості випадків використання (навіщо обтяжувати дизайн залежностями до іншого, який ледь коли-небудь застосовується?).
Тому що концептуально ми насправді не відірвалися Foo
від цього Bar
. Ми щойно зробили це, щоб заголовок Foo
не потребував стільки інформації про заголовок Bar
, і це не настільки суттєво, як дизайн, який справді робить ці два абсолютно незалежними один від одного.
Вбудований сценарій
Це дійсно для ширших баз коду, але інший метод, який я вважаю надзвичайно корисним, - це використання вбудованої мови сценаріїв принаймні для найвищого рівня вашої системи. Я виявив, що мені вдалося вбудувати Lua за день і мати можливість рівномірно викликати всі команди в нашій системі (команди були абстрактні, на щастя). На жаль, я натрапив на блокпост, де чорти не довіряли запровадженню іншої мови і, можливо, найбільш химерно, з виконанням як найбільшою підозрою. Однак, хоча я можу зрозуміти інші проблеми, продуктивність повинна бути проблемою, якщо ми використовуємо сценарій лише для виклику команд, коли користувачі натискають кнопки, наприклад, які не виконують здорових циклів (що ми намагаємось зробити, турбуйтеся про наносекундні відмінності у часі відгуку для натискання кнопки?).
Приклад
Тим часом найефективнішим способом, яким я коли-небудь був свідком після виснажливих методів скорочення часу компіляції у великих кодових базах, є архітектури, які справді зменшують кількість інформації, необхідної для роботи однієї речі в системі, а не просто від'єднання одного заголовка від іншого від компілятора перспектива, але вимагаючи від користувачів цих інтерфейсів робити те, що їм потрібно робити, знаючи (як з точки зору людини, так і з точки зору компілятора, справжня розв'язка, що виходить за межі залежностей компілятора) - мінімальний мінімум.
ECS - це лише один приклад (і я не пропоную вам використовувати його), але зустрічаючи його, ми показали, що ви можете мати справді епічні кодові бази, які все ще створюють напрочуд швидко, із задоволенням використовуючи шаблони та безліч інших смаколиків, оскільки ECS, автор природно, створює дуже розв'язану архітектуру, де системам потрібно знати лише базу даних ECS і, як правило, лише декілька типів компонентів (іноді лише один), щоб зробити свою справу:
Дизайн, дизайн, дизайн
І такі види роз'єднаних архітектурних конструкцій на людському, концептуальному рівні є більш ефективними з точки зору мінімізації часу компіляції, ніж будь-який із методів, які я досліджував вище, коли ваша кодова база зростає та зростає та зростає, оскільки це зростання не відповідає вашому середньому підрозділ компіляції, що множить інформацію про кількість, необхідну при компіляції, і час зв’язку для роботи (будь-яка система, яка вимагає від вашого середнього розробника включити навантажувальний матеріал, щоб зробити що-небудь, також вимагає від них, а не просто компілятора знати про велику кількість інформації, щоб зробити що-небудь ). Він також має більше переваг, ніж скорочений час збирання та розкручування заголовків, оскільки це також означає, що вашим розробникам не потрібно багато знати про систему, крім того, що потрібно відразу, щоб зробити щось із нею.
Наприклад, якщо ви можете найняти досвідченого розробника фізики для розробки двигуна фізики для вашої гри AAA, який охоплює мільйони LOC, і він може почати дуже швидко, знаючи абсолютний мінімум інформації, що стосується речей, таких як типи та інтерфейси. а також ваші системні концепції, то це, природно, буде перекладено на зменшену кількість інформації як для нього, так і для компілятора, щоб вимагати побудови свого фізичного двигуна, а також перекладати до значного скорочення часу складання, загалом маючи на увазі, що немає нічого подібного до спагетті в будь-якій точці системи. І саме це я пропоную розставити пріоритет над усіма цими іншими методами: як ви проектуєте свої системи. Вичерпання інших прийомів буде обмерзанням зверху, якщо ви це зробите, інакше,