Збентежуючи, я представив "спільну" бібліотеку, названу як таку, в командному середовищі пару десятків років тому. Тоді я не дуже розумів динаміку того, що могло статися у слабко узгодженій команді за декілька місяців.
Коли я представив це, я подумав, що я дав зрозуміти, а також задокументував, що для тих речей, які ми всі погоджуємось, ми вважаємо корисними щодня, що це призначено бути бібліотекою мінімалізму, і що бібліотека не повинна залежати ні від чого іншого, крім стандартна бібліотека, щоб її було максимально просто розгорнути в нових проектах. У той час я думав, що це наше власне невелике розширення до стандартної бібліотеки для речей, які в нашому конкретному домені щодня знаходили корисні.
І це почалося досить добре. Ми почали з математичної бібліотеки ( common/math*
) процедур, яку ми всі використовували щодня, оскільки ми працювали в комп'ютерній графіці, яка часто була важкою для лінійної алгебри. А оскільки ми часто взаємоділи з кодом С, ми погодилися на деякі корисні функції утиліти, такі як find_index
, на відміну відstd::find
в C ++ повертає індекс до елемента, знайденого в послідовності замість ітератора, який наслідував, як працюють наші функції C - речі такого роду - трохи еклектичні, але мінімалістичні і досить широко використовуються, щоб залишатися знайомими і практичними для всіх і миттєве знайомство є надзвичайно важливим критерієм, оскільки я бачу це у спробі зробити все, що є "загальним" або "стандартним", оскільки якщо воно справді є "загальним", воно повинно мати таку звичну якість про нього як результат його широкого прийняття та щоденне використання.
Але з часом дизайнерські наміри бібліотеки вислизнули з моїх пальців, коли люди почали додавати речі, які вони використовували особисто, які, як вони думали, можуть бути корисними комусь іншому, лише знайти того, хто більше не використовує її. А пізніше хтось почав додавати функції, які залежали від OpenGL для звичайних GL-процедур. Далі ми прийняли Qt, і люди почали додавати код, який залежав від Qt, тому вже загальна бібліотека залежала від двох зовнішніх бібліотек. У якийсь момент хтось додав загальні підпрограми шейдерів, які залежали від нашої бібліотеки шейдерних програм, і в цей момент ви навіть не змогли розгорнути його в новому проекті, не ввівши Qt, OGL та нашу бібліотеку шейдерів та написання конкретних програм. нетривіальний сценарій збірки для вашого проекту. Так воно перетворилося на цей еклектичний, взаємозалежний безлад.
Але я також виявив, обговорюючи, що слід, а що не слід входити в цю бібліотеку, що те, що вважається "загальним", може легко перетворитись на дуже суб'єктивну ідею, якщо ви не встановите дуже жорстке правило, що "загальне" що кожен прагне вважати корисним щодня. Будь-яке ослаблення стандартів, і воно швидко погіршується від речей, які кожен щодня вважає корисними, до того, що один розробник вважає корисним, що може мати користь комусь іншому, і в цей момент бібліотека дуже швидко руйнується в еклектичний безлад .
Але крім того, коли ви досягнете цієї точки, деякі розробники можуть почати додавати речі з тієї простої причини, що їм не подобається мова програмування. Можливо, їм не сподобається синтаксис циклу for або виклик функції, і тоді бібліотека починає наповнюватися речами, які просто борються з основним синтаксисом мови, замінюючи пару рядків прямого коду, який насправді не є дублювання будь-якої логіки до єдиного короткого рядка екзотичного коду, лише знайомого розробнику, який представив таку стенографію. Тоді такий розробник може почати додавати більше функціональних можливостей до загальної бібліотеки, реалізованої за допомогою таких скорочень, в цей момент значні розділи спільної бібліотеки переплітаються з цими екзотичними стенограмами, які можуть здатися красивими та інтуїтивно зрозумілими розробнику, який представив її, але некрасивим та чужим та важко зрозумілим для всіх інших. І в цей момент я думаю, ви знаєте, що будь-яка надія зробити щось по-справжньому «спільне» втрачається, оскільки «спільне» та «незнайоме» є полярними протилежними ідеями.
Отже, там існують усілякі банки з хробаками, принаймні у слабко координованому командному середовищі, з бібліотекою з широкими амбіціями та настільки ж узагальненими, як просто "загальновживані речі". І хоча основна проблема, можливо, була слабкою координацією, перш за все, принаймні кілька бібліотек, призначених слугувати більш єдиному призначенню, як бібліотека, призначена для забезпечення математичних процедур і нічого іншого, ймовірно, не погіршиться настільки істотно з точки зору її чистоту дизайну та залежності як "загальну" бібліотеку. Отже, в ретроспективі я думаю, що було б набагато краще помилитися на стороні бібліотек, які мають набагато чіткіші наміри дизайну. З роками я також виявив, що вузька за призначенням і вузька у застосуванні - принципово різні ідеї.
Крім того, я, правда кажучи, принаймні трохи непрактичний і дбаю, можливо, трохи надто естетичний, але те, як я схильний сприймати своє уявлення про якість бібліотеки (а може бути, навіть і "краси") судять більше за її найслабшою ланкою, ніж його найсильніший, аналогічним чином, що якщо ви подарували мені найбільш апетитну їжу в світі, але, на цю ж тарілку, туди щось гнило, що пахне по-справжньому погано, я, як правило, хочу відкинути всю тарілку. І якщо ви схожі на мене в цьому плані і робите щось, що запрошує всілякі доповнення як щось, що називається "загальним", ви можете виявити, що дивитесь на цю аналогічну тарілку, де щось гниє збоку. Так само я вважаю, що добре, якщо бібліотека буде організована, названа та задокументована таким чином, щоб вона не була ' t з часом запрошувати все більше і більше доповнень. І це навіть може стосуватися ваших особистих творінь, оскільки я, безумовно, створив тут і там деякі гнилі речі, і це "заплямовує" набагато менше, якщо його не додають до найбільшої тарілки. Розділення речей на невеликі, дуже єдині бібліотеки також має тенденцію до кращого роз'єднання коду, якщо тільки за допомогою чистої чесноти, що починати зв'язувати все стає набагато менш зручно.
Дедуплікація коду була забита в мене протягом багатьох років, але я відчуваю, що мені слід цього разу спробувати.
Те, що я можу запропонувати у вашому випадку, - це почати полегшувати діблікацію коду. Я не кажу, щоб копіювати та вставляти великі фрагменти погано перевіреного, схильного до помилок коду навколо чи чогось подібного, або дублювання величезної кількості нетривіального коду, який має гідну ймовірність вимагати змін у майбутньому.
Але особливо, якщо ви налаштовані створити "загальну" бібліотеку, для якої я припускаю, що ваше бажання - створити щось широко придатне, багаторазове використання, і, можливо, в ідеалі щось, що ви вважаєте таким же корисним сьогодні, як і десятиліття відтепер , то іноді вам може знадобитися або потрібне певне копіювання, щоб досягти цієї невловимої якості. Оскільки дублювання насправді може служити механізмом розв'язки. Це так, як якщо ви хочете відокремити відеоплеєр від MP3-плеєра, то вам, принаймні, потрібно дублювати деякі речі, наприклад, акумулятори та жорсткі диски. Вони не можуть ділитися цими речами, інакше вони нерозривно пов'язані між собою і їх не можна використовувати незалежно один від одного, і в цей момент люди можуть більше не цікавитись пристроєм, якщо все, що вони хочуть, - це відтворення MP3-файлів. Але через деякий час після того, як ви розділите ці два пристрої один від одного, ви можете виявити, що MP3-програвач може отримати вигоду від іншої конструкції батареї або меншого жорсткого диска, ніж відеоплеєр, і тоді ви більше нічого не дублюєте; те, що спочатку почалося як дублювання, щоб дозволити цьому взаємозалежному пристрою розділитись на два окремі незалежні пристрої, згодом може виявитись конструкцією та реалізацією, які вже не є зайвими.
Варто розглянути речі з точки зору того, хто використовує бібліотеку. Ви дійсно хочете використовуватибібліотека, яка мінімізує дублювання коду? Швидше за все, ви цього не зробите, тому що той, який є, буде, природно, залежати від інших бібліотек. А ці інші бібліотеки можуть залежати від інших бібліотек, щоб уникнути дублювання їхнього коду тощо, поки вам не знадобиться імпортувати / зв'язати 50 різних бібліотек, щоб отримати лише базовий функціонал, наприклад завантаження та відтворення аудіофайлу, і це стане дуже непростим. . Тим часом, якщо така аудіобібліця навмисно вирішила дублювати деякі речі тут і там, щоб досягти своєї незалежності, це стає набагато простіше використовувати в нових проектах, і, швидше за все, її не потрібно буде оновлювати майже так часто, оскільки вона виграла ' не потрібно змінюватись внаслідок зміни однієї його залежної зовнішньої бібліотеки, яка може намагатися виконати набагато більш узагальнену мету, ніж те, що потрібно аудіобібліотеці.
Тому іноді варто свідомо вибрати, щоб трохи дублювати (свідомо, ніколи не лінь - насправді з ретельності), щоб роз’єднати бібліотеку та зробити її незалежною, оскільки завдяки цій незалежності вона досягає більш широкого спектру практичної застосовності та рівномірна стабільність (більше ніяких афективних муфт). Якщо ви хочете розробити найбільш можливі багаторазові бібліотеки, які триватимуть вас від одного проекту до наступного і протягом багатьох років, то, крім того, щоб звузити його обсяг до мінімуму, я б фактично запропонував би розглянути можливість їх дублювання. І, природно, пишіть одиничні тести і переконайтесь, що вони справді ретельно перевірені та надійні в тому, що вони роблять. Це лише для бібліотек, які ви дійсно хочете витратити час на узагальнення до точки, що виходить далеко за межі одного проекту.