Good practice, bad practice, хард код та сучасні практики програмування

Я останнім часом досить сильно віддалився від програмування та й в цілому в мене розробка на контроллерах під досить специфічні задачі
Мені стало цікаво як зараз змінилось ставлення до написання коду.

Коли я ще навчався то дуже було популярно писати «правильний код за якимись умовними практиками», вивчати патерни програмування та всяке таке інше.

Коли ж я почав працювати то реальність виявилось такою що це «правильне програмування» в якийсь момент перетворювало код просто в якусь лапшу з абстракцій, тоді в мій код почали повертатись глобальні змінні, потім патерни стали як це сучасно казати «антипатернами», потім прийшло поняття що високі рівні абстракції роблять код просто не функціональним і те що називають «лаконічним спрощенням для розуміння іншими програмістами» перетворилось на якусь складну махіну з якою розбиратись набагато довше ніж зробити це по дубовому без тисяч перевірок, я почав писати код з описом просто того шо можна передавати в функції а що не можна(були перевірки але мінімальна кількість самих критичних), бо по перше той хто використовує функції має сам дбати про валідність данних, по друге прийшло розуміння того що ретурни з еррор кодами це дуже цікаво авжеж, а толку з них якщо їх треба обробляти і шось вирішувати шо робити далі і простіше просто ці кейси прописувати вже переписуючи функцію під конкретну задачу, а ніж писати одну функцію під все на світі хоча в конкретних випадках зі 100 перевірок треба одна(якої в момент написання функції авжеж не було враховано)

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

Про всякі інкапсуляції та поліморфізми казати нічого не буду, в мене більш сішечка а не плюси.

Ну і так, ще одне питання, звідки взялась гонитва за останніми версіями стандартів які вимагають, так інколи добавлять круті штуки, але якщо всього вистачає наприклад на с++11 нащо намагатись переходити на 17? я про таке час від часу чую від інших розробників, так само як і оновлення фреймворків.
Для мене взагалі в якийсь момент стало золотим правилом що фреймворк та компілятор на початку проекту скачується на окрему флешечку і до кінця проекту ніколи не оновлюється(дякую певним індусам з їх оновленням шо воно почало відвалюватись в рандомних місцях в рандомні моменти бо вони «покращили»)

Ну і так, хотів би почути яке зараз ставлення взагалі до «правил написання гарного коду», як і у компаніях так і як змінювалось ваше особисте ставлення до цього з часом

Нащо, бо мабуть скоро буду повертатись в програмування, і думаю як себе продавати, як спеціаліста який просто може виконувати поставленні задачі, чи всеж відкривати ці сучасні книжечки про правила програмування і готуватись до того що структурованість за певними принципами є більш головне ніж якісна і швидка розробка

Ну і так, просто поговорити

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

На співбесіді:
"

структурованість за певними принципами є більш головне ніж якісна і швидка розробка

"
Коли вже працюєш:

швидка розробка

Ще грошей меньше дають, якщо продавати себе як:

спеціаліста який просто може виконувати поставленні задачі
швидка розробка

Зазвичай — ага, і потім воно не розгортається на проді і в усіх релізна лихоманка. Постійні овертайми, з менталітетом морскої піхоти — без сну та їжі, череда хотфіксв та постійні інтриги та скандали. Плавали знаємо, в проектах де суттєві проблеми з процесами — працювати це ж просто мрія ІТ спеціалістів.
«If you think good architecture is expensive, try bad architecture. —Brian Foote and Joseph Yoder»

Коли ж я почав працювати то реальність виявилось такою що це «правильне програмування» в якийсь момент перетворювало код просто в якусь лапшу з абстракцій

Все так. Особливо за «інфоциганами» (буде колись кращий термін?) як Боб Мартін, якого як раз пропагують першим як взірець на кого рівнятись.

А потім думаєш, яке відношення SOLID має до обробника переривання :)

Але це знає (навіть якщо публічно каже зворотнє) кожний з реальним досвідом. Я так бачу, ви тільки почали надбувати цей досвід. Ну, все ще попереду...

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

Значить, погано шукали. Чим defines погані:

1. (Найпростіше) уявіть собі, що вам треба мати foo::MAX_ELEMENTS і bar::MAX_ELEMENTS. Якщо вони задані кожний в своєму класі або просторі імен, вам легко розрізнити, який прийняти в конкретному випадку. Якщо ви дали using на обидва, то компілятор скаже, що без уточнення він не захоче приймати таке імʼя. А в препроцесорі може просто замінитись значення на інше — і шукайте потім помилку...

2. Дефайн нетипизований (ну якщо ви його не написали в дусі ((int64_t)1234)), константа типизована.

3. А все ще складніше з функціональними дефайнами. Найкласичніший приклад: `#define max(a,b) a>b?a:b` - тут одразу дві проблеми — приоритітети і багаторазове обчислення. Якщо думаєте, що завжди зможете побачити проблему — ні, не завжди. Якщо багато каскадів дефайнів, складні вирази і ви втомились — щось пропустите поза увагою.

Ну і так, хотів би почути яке зараз ставлення взагалі до «правил написання гарного коду», як і у компаніях так і як змінювалось ваше особисте ставлення до цього з часом

Вони корисні і мають бути. Але — ті, що дійсно корисні, і відповідають домену призначення.

як Боб Мартін

Товсто. Та якщо ви знайдете щось інше від інших авторів то розшарьте.
Якось так сталось що абсолютно про те саме пише : і Бйорн Страуструп і Ендрю Тандербаум, і Джошуа Блох, і Мартін Фаулер, і Кент Бек. В цілому то вони посилаються на інших провідних вчених та кращих інженерів індустрії.

Товсто.

Ще не починав.

Якось так сталось що абсолютно про те саме пише

Тобто читати і аналізувати ви не вмієте або не хочете, якщо у вас Фаулер і Таненбаум пишуть «абсолютно про те саме», що і мартінова маячня. Ну хоча б тоді подивіться критику його «творів», якщо самі не аналізуєте.

Хм, ну наприклад.
«Всього» в C++11 нема. Він зробив логічне замкнення того, що було, і багато дірок закрив, все так. Але в окремих областях його рішень або нема, або вони ж дуже часткові.
В C++17 зʼявився stringview. Наскільки це важливо? Для двох моїх останніх проектів — аж ніяк. Але я знаю такий, де це підвищило ефективніть раза в 2.
C++14 має lambda captures. Знову спрощення у деяких специфічних місцях.
Я більше невдоволений тим, що деякі речі мали б бути зроблені надцять років тому. C23 ввів усякі ckd_add(). Хоч щось для безпеки деяких операцій, хоча і 10% від того, що було треба. C++20 ввів bit_cast. Для маніпулювання структурами при роботі з файловими форматами або памʼяттю спеціалізованих пристроїв — критично. Раніш залагались на режим компіляції і вручну вставлені барʼєри. Через тупі гальма в комітетах речі, що мали б бути ще коли я в школу пішов, тільки починають зʼявлятись...
То чому б не використати те, що є і легко доступно?

От мені цікаво чому «сучасні». За великим рахунком принципово з 60-х років минулого сторіччя нічого на змінилось. Так відбулось дуже багато еволюційних покращень, різноманітних, а також суттєву еволюцію здійснив хард. Також інтернет — змінив світ і наш спосіб життя. Та в цілому — усе що ми маємо, це подальший розвиток ідей Джона Блекуса з IBM — тобто FORTRAN.
Що тоді був інженерний підхід до створення ПЗ типу NASTRAN, що чисто утілітариний прикладний — типу на швидко отримати якісь розрахунки після чого в програмі не буде ніякої потреби — її не буде ніякого сенсу підтримувати. Під другий підхід навмисно створювали мови програмування типу : BASIC, COBOL або PL/1.
Що правда виник і феномен COBOL, коли виявилось, що створену на швидко систему яка автоматизує якийсь бізнес процесс — підтримують десятками років. При цьому в неї дуже важко вносити якісь зміни, переносити між апаратними архітектурами тощо. І це саме через вкрай низку структурну якість, експериментальне програмування, відсутність документації і т.п.

Та в цілому — усе що ми маємо, це подальший розвиток ідей Джона Блекуса з IBM — тобто FORTRAN.

Це ви вже перебільшуєте. Яке відношення до Фортрану мають, наприклад, функціональні замкнення, або ACID-принципи баз даних? ;)
Да, він був значною віхою. Але при цьому може 10% ідей йдуть з нього.

Подивіться на список винаходів недавнього часу, що важливі зараз — там сотні пунктів.

Функціональне програмування це про Lisp який по факту ровесник FORTRAN. Якраз перша чисто прикладна мова, для наукових робіт по штучному інтелекту (над яким почали працювати ще до створення комп’ютера, власне і сам комп’ютер результат цієї роботи).
Принципи розробки — усі ті самі, умовно те що робили за допомогою реле та електронних ламп поступово стали робити мікрочіпами. Але логічно пристрій працює абсолютно так само — складає, інвертує та здвигає і усе робиться логічними елементами І/Не на базі електричного ключа.
Принципи розробки софта залишились ті самі, що і в FORTRAN.
Щодо : баз данних, інтернет та WWW, відео прискорювачів та 3D та купи усього іншого типу відео дзвінків, це інші винаходи. Існуючої базису було достатньо для того щоби реалізувати ці винаходи.

Функціональне програмування це про Lisp який по факту ровесник FORTRAN.

1. Про лямбда-зчислення, яке з 1930-х.
2. Да, ровесник. Але вже не сам Fortran.

Існуючої базису було достатньо для того щоби реалізувати ці винаходи.

«Існуючого базису у вигляді релейних схем було достатньо, щоби реалізувати ці винаходи». (Бо на ніх можна зробити логічні елементи, а далі шлях зрозумілий.)
Самі вже розумієте, чому ваш підхід, мʼяко кажучи, неконструктивний, або ще будете сперечатись?

Я вважаю, що коли ми говоримо про якість коду, треба, перш за все, розділяти (назвемо це так, вибачте, не дуже знайомий з термінами):

— алгоритмічну якість коду (умовно кажучі, краще використовувати О(1) ніж О(2) алгоритми, якщо можливо) — тобто, скільки ресурсів заліза потрібно для виконання коду і рішення задачі
— синтаксичну якість коду

До останньої якраз і відносяться всілякі «шаблони», ООП, процедурне чи функціональне програмування — і все це треба не компʼютеру, а перш за все нам, мавпам, для розуміння складного коду і спрощення його підтримки. Бо компілятор все одно що «спагетті», що розбитий по модулях і обʼєктах (чи функціях) код перетворить і оптимізує до невпізнанності (для нас, мавп). Питання виключно в тому, що розуміти, міняти та підтримувати «спагетті» значно важче нам. Так само і різниці між захардкоженими значеннями, константами чи дефайнами на рівні машинного коду ви вже не побачите. А ось підтримувати це — зовсім інша історія.

Тому ще до того, як ми почнемо обговорювати кращі практики щодо написання коду і які саме має сенс використовувати — слід визначитись, чи буде взагалі той код розвиватись та підтримуватись, кудись переноситись. Чи будуть змінюватися ті чи інші значення — і вже після цього обирати шаблони та правила, які будуть використані при написанні коду.

Бо ООП дуже зручна парадігма, але коли ви пишете дуже простий скрипт на 5 дій, і немає жодних ознак що в осяжній перспективі вам його треба підтримувати чи розвивати — створювати для цього обʼєкт — явно забагато, тут навіть різниці між «спагетті» та розділенням 5 стрічок на 2 процедури з 2 та 3 діями відповідно — просто немає різниці.

Так само, якщо зовнішнє АПІ є тільки одне, іншого немає в природі і не проглядається навіть на стратегічно далекому обрії — писати узагальнені класи-інтерфейси для розділення бізнес-логіки вашої програми і зовнішнього апі — теж явне перебільшення витрат ваших ресурсів і переускладнення вашого коду. Простої «обертки» буде достатньо.

Звісно, є загальні вимоги до коду, як то іменування функцій та змінних, форматування коду і таке інше — що потрібно для більш легкого розуміння цього коду іншим програмістом. Але, знов таки, для компʼютера це не має жодного значення.

Тож, підсумовуючи (у порядку важливості, як на мій хлопській розум):

— намагайтесь використовувати найбільш оптимальні алгоритмічні рішення.
— намагайтесь дотримуватись загальноприйнятого для обраної мови стилю коду
— намагайтесь дотримуватись вимог до коду вашого проєкту.
— намагайтесь розділяти все, що може змінюватись (наприклад, конфігурація — адреси зовнішніх апі, адреси БД і таке інше) і те, що є константою для вашого проєкту, але змінює значення по-замовчуванню для сторонніх бібліотек — винесіть це в спеціальні файли конфігурації. (тобто уникайте хардкоду як такого), але, якщо ці значення «розкиданні» по кільком функціям чи файлам/модулям — інакше принципової різниці немає, достатньо винести в початок файлу, просто для зручності.
— уникайте використання будь-якого правила чи шаблону суто заради «щоб було» — наприклад, якщо зовнішнє АПІ використовується більше ніж в кількох різних модулях вашого проєкту — зробіть просту «обгортку», якщо ж це використовується виключно в 2 функціях у одному модулі, сенсу в цьому небагато. Як і написання узагальненого інтерфейсу для кількох можливих різних зовнішніх АПІ, якщо в природі існує лише одне.

Дякую за відповідь, я всеж про більш примітивні погані практики

наприклад використання войд пойнтера, я весь час чув шо так не можна, треба або темплейти або шось подібне, в якийсь момент в мене була велика частина роботи перекидувати данні з одного вхідного масиву по іншим за певними принципами, я просто віднісся до цього як до «абстрактних» данних, войдпоінтер, розмір, крок і кидаємо як попало, так само дурні оптимізації типу переносили не 8 uint8_t а два uint32_t( оптимізація мала б це зробити наче за мене, але чомусь не зробила)

Так само глобальні змінні, я втомився тягати через 10 функцій один вказівник, зробив массив глобальним і просто використовую де хочу.

Знов таки до попершого, темплейти, все життя мені казали що якщо функція під один тип данних ще раз викликається для іншого це ок, якщо в друге переписуємо на темплейт.
В мене перейшло до того що якщо ця функція не змінюється частіше ніж раз на 2 місяці я просто її копіюю під інший тип і взагалі намагаюсь так робити бо виникали ситуації коли різні типи потребували різної доробки, спочатку робимо універсальне потім перероблюємо під конкретне, я так кілька разів погорів, писав лаконічно вийшла кракозябра і тепер просто копіюю код(можу собі дозволити на контроллерах не такі обширні задачі)

от з цим доречі в мене питання до вас, я інколи використовую не зрозумілі для середнього програміста(для нормального зрозумілі але зачасту вони не широкого вжитку) конструкції типу:
do {..} while (0);
Массив вказівників на функції

Це доречі круто і зручно, але скажімо так, коли я сам з таким вперше зіштовхнувся то не зовсім зрозумів, та і інші теж носом крутили, а потім як зрозумів....

Арифметика вказівників, це взагалі те що я люблю, але мене хотіли за це потім на стовпі повісити

мені взагалі якщо чесно важко згадати що таке гарні і погані практики, але я просто памятаю що те що я писав за останні роки дуже-дуже сильно відрізнялось від того як мені казали гарно писати 15 років тому

наприклад використання войд пойнтера, я весь час чув шо так не можна

Я взагалі не люблю «абсолютних» правил. Тут (на мій погляд, знову ж таки) справа не в тому що «не можна» а в тому, що компілятор чи аналізатор коду не зможе спіймати помилку програміста, тобто вірогідність помилки росте.

Так само глобальні змінні,

Абсолютно те саме, вкрай складно контролювати коли саме і з якої частини коду може змінитися значення.

от з цим доречі в мене питання до вас, я інколи використовую не зрозумілі для середнього програміста(для нормального зрозумілі але зачасту вони не широкого вжитку) конструкції типу:
do {..} while (0);

Не вважаю себе експертом з програмування. Але як на мене — не бачу нічого не зрозумілого.

Массив вказівників на функції

Це доречі круто і зручно, але скажімо так, коли я сам з таким вперше зіштовхнувся то не зовсім зрозумів, та і інші теж носом крутили, а потім як зрозумів....

Ох, цілком вас розумію, я це побачив ще в університеті, як перейшов (просто заради цікавості) з pascal на С і там таке можна було робити — вкрай зручно, мені це тоді здавалось прям кіллер фічей ;D

Доречі про практики. Я, якось так сталося, пішов шляхом SysAdmin-DevOps і на якийсь час закинув С, а потім почав більше писати на Python (він для автоматизації ближче буде, ніж С) — але весь час дивився на інші мови — і мене якось дуже сподобався Rust, суто з інженерної точки зору, як там організована робота з памʼятю, вказівниками і ідея про те, що «небезпечний» код можна відокремити від «безпечного» — який доволі строго перевіряється ще при компіляції. Зараз переписую свої пет-проєкти (це всіляки автоматизації та боти для дому і повсякденних задач, невеличкі проєкти загалом) на Rust. Так до чого це я. Багато з перерахованих практик там так чи інакше реалізовані і «безпечні».

приємно чути що від «абсолютних практик» вже відійшли, раніше це як закон ома вимагали

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

Доречі так скмо я ставлюсь до тестів, якщо ти розумієш шо ти і як робиш і як воно працує то вони не потрібні.

з глобальними змінними мене так само(може через те що в мене маленька команда була) але ти сам маєш контролювати що і коли ти змінюєш

ду вайл(0) це або в мене знайомі такі, або магія бо 90+% не розуміють нащо і нахіба

раст я дивився, може я не доріс, але не побачив сенсу, я сам все і так контролюю і не бачу причин нащо це перекладати на процесор(так так, нижчий поріг входу, і все таке) так само як і з більш «високорівневими мовами» ти витрачаєш час на те щоб зрозуміти як вони все контролюють який виходить таким самим ак розібратись як самому все контролювати

Та й взагалі те що звикли називати високорівневими мовами(джава пітон) хоча навіть С це високорівнева мова, але не суть, для мене це просто біль, ці равні абстракції, коли була задача на джаві в ргба зображенні змінити байти місцями для ргб на виході, з мене ти поти зійшло, бо я не розумів чого така проста задача так складно вирішується

Я от ще згадав, для мене ще з поганих пракик часто було виділення глобальних змін замість динамічного виділення памяті, може це через специфіку того що в мене контроллер і я працював по «гіршим» сценаріям і варіант коли памяті не вистачило це крах системи.

Так до суті, є сенс досвідченому програмісту зараз читати щось про гарні практики чи просто достатньо не бути мудаком і писати як пишеться?

приємно чути що від «абсолютних практик» вже відійшли, раніше це як закон ома вимагали

Ну я ж не казав за всіх. Це моє особисте бачення.

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

Доречі так скмо я ставлюсь до тестів, якщо ти розумієш шо ти і як робиш і як воно працує то вони не потрібні.

Ось тут не погоджусь. Бо коли коду небагато, то дійсно, все здається очевидним (але не факт — регулярні вирази можуть виглядати «маленькими», а давати доволі непередбачувану поведінку)

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

А ось тести починають грати важливу роль, коли кодова база велика і змінюється різними людьми — знов таки, коли тобі треба змінити одну функцію/метод це може дати взагалі неочевидну зміну поведінки цілого модуля. І краще побачити це все на тестах, ніж в роботі.

Але так, якщо у вас програми на 30 стрічок коду — написання тестів може бути марною тратою часу, простіше передивитись (принаймні, так може здаватись). Взагалі я скоріше за тести і за статистичний аналіз. Просто не треба відноситись до цього як до «срібної кулі» — це не виключає помилок, а лише зменшує їх вірогідність і кількість. Тобто, все те саме — ніякого «абсолюту».

Так до суті, є сенс досвідченому програмісту зараз читати щось про гарні практики чи просто достатньо не бути мудаком і писати як пишеться?

Особисто я вважаю, що знання за плечами не носити, та й вчитись ніколи не запізно ;)

приємно чути що від «абсолютних практик» вже відійшли, раніше це як закон ома вимагали

Хто ці «вони» хто вимагали?
На кожному проекті своя специфіка, і вимоги були дуже різні.

аналізатори полегшують життя але знижують увагу і в кінцевому результаті виходять проблеми.

Ну так не знижуйте увагу. Вибачте, я серйозно.

Доречі так скмо я ставлюсь до тестів, якщо ти розумієш шо ти і як робиш і як воно працує то вони не потрібні.

«_Якщо_». А потім зʼясовується, що не так зрозумів опис функції — або там дійсно помилка.
Тести вони також і для того, щоб ловити проблеми в оточенні і в бібліотеках.

хоча навіть С це високорівнева мова

Була 50 років тому. Зараз це переносимий асемблер.

Так до суті, є сенс досвідченому програмісту зараз читати щось про гарні практики чи просто достатньо не бути мудаком і писати як пишеться?

Читати — треба.
Використовувати некритично — ні.
Почитайте краще ось це: www.joelonsoftware.com/2002/05/06/five-worlds
Сподіваюсь, буде досить щоб зрозуміти, чому всі ці суперпрактики не будуть автоматично підходити.

«Вони» це була вся спільнота 15 років тому, виклав шмат коду з питанням, мене заклювали за те що не первіряв приходження нулпоінтера в функцію і ще якась муть на валідність данних, а на питання так і не відповіли.

Дякую за посилання, дуже цікавий дядько.

Добре, давайте від абстрактного до конкретного.
Задача написати функцію по переміщенню данних за допомогою двох ДМА
приймає(номер дма, куди класти, скільки класти, номер другого дма, куди класти, скільки класти)
Специфіка — контроллер, вхідні данні тільки з коду, нічого стороннього не прилетить, проект довгостроковий, не дуже великий, на 10 людей, код не на продаж

варіант перший, законфігурував, штовхнув, в описі написав що треба вирівнювати вказівник і який дма з якого місця які данні тягне. все

Варіант другий, перевірив вирівненність адресси, що не нулпойнтер, перевірив що номери дма існують а не «33», перевірив що номера дма не співпадають, що адресси не співпадають, що розмір данних адекватний.

Написав опис як в перший раз і додав опис оцих всіх еррор кодів.

плюс другого варіанту — якщо хтось шось передасть не те, то буде простіше відслідковувати що саме не те, кожен студентик буде отримувати гарну красиву відповідь про те що він не так зробив

Плюс першого — простий локанічний код, просто слідкуєш шо куди кладеш, все працує.

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

Банально просто ну запустив 1 варіант, критікал ерор, брекпоінт, перезапустив подивився шо там ти напхав.
Другий варіант, запустив — отримав повідомлення шо ось тут шось не так, подивився шо у змінній

Тобто різниця тільки в тому що спіймаєш ти краш системи від помилки чи ні, ну і можливо якесь логування чи можливість автоматичного тестування

мене заклювали за те що не первіряв приходження нулпоінтера в функцію і ще якась муть на валідність данних, а на питання так і не відповіли.

Це зветься defensive programming. Воно має бути на границі відповідальности (наприклад, коли приймаєш дані з Інтернету), а чи робити його всередині — залежить від поточних задач. Для складного дебагу — має бути.

перший мені здавався більш зручним, і логічним

Тобто другий? (де перевірки)

Банально просто ну запустив 1 варіант, критікал ерор, брекпоінт

Угу. А тепер давайте ускладнімо.
Варіант 1: critical error передати нічим, breakpoint поставити нема можливости. Залізяка, наприклад, на точці за 200 км від вас, звʼязку нема. Людина на місці має здібности типу сказати «тут одна лампочка чомусь червона». Що робитимете?
Спольскі такі вимоги згадує. І неважливо, це пральна машина чи частина блоку керування реактором атомного підводного човена — все одно ви дебагером не залізете. І що робитимете?

Варіант 2: Я читав про одну воєнну АТС, яка по кожній хвилі вхідного струму (220) просто ресетилась. В постійній памʼяті поточні активні зʼєднання і буфер набору дзвінка, і все. Решта — не встиг за 20 мс, іди на наступне коло.
(Це був натяк на те, що у складних системах такого типу за вихід з проблеми може відповідати щось вище рівнем.)

Може, у вас просто запише адресу де вилетіло і перезапустить. Колись Microsoft з такого почала збір інформації, де її програми лажають. 90% вилетів в Office було на одну адресу, швидко знайшли і виправили.

Варіант 3: Ну добре, хай такої віддалености нема. Але інша ситуація, у мене з VoIP вона десь постійна. Запускаєш дзвінок і ловиш гігабайт логу. І це добре, що лог є — в ньому написано, що не так, і можна відслідкувати, звідки прийшли некоректні значення. А дебагер встановили на таку точку неможливо, дзвінок обірветься через секунду затримки даних, поки ви будете перемикатись на вікно дебагера. Тоді тільки другий метод, дефензівна перевірка всіх параметрів (і своїх результатів також) і запис в лог, якщо щось не так, з мʼякою відмовою.

Варіант 4: Або у мене зараз в одному проекті міні-задача — поміняти таймстампи (unixtime) з секунд в double на наносекунди в long. І тут Python, тому int і float спокійно плутатимуться. Що робити? Я в кожному критичному місці вставлю щось на зразок «assert ts >= NY2024NS» і буду гнати тести, поки не перестане падати на ассертах. Потім більшість видалю, хоча парочку, мабуть, перетворю на запис в лог.

Розумієте? Оточень багато варіантів, вимог багато варіантів. Нема універсального методу і нема єдиного підходу на все. Десь треба перевіряти, десь ні. Десь краще трапатись, десь відповідати кодом помилки, десь повертати ok. Універсальне тільки одне — без голови не спрацює.

Я відповів на запитання? ;)

Тобто другий? (де перевірки)

Так описався.

В цілому так, ви дали відповідь на моє питання — гарні практики, це ті які створюються головою способом мислення

Ну якось так і працую, якшо це зараз норма це добре

ніякий аналізатор коду не зможе зловити помилку

От тут вже не правда ваша, сучасні ловлять навіть середні помилки. Власне як і досвідчений або добре тренований розробник виловлює помилки лише по їх зовнішнім проявом, на ревью. Тренуванням можна набути знань які досвідом набуваються роками. Той же літкод для прикладу, напевно не стільки про алгоритми, скільки про стиль та культуру низькорівневого кодування. От не дасть він засабмітити алгоритм в якому не перевірені граничні умови. наприклад якись параметр функції типу int (4 байти зі знаком), але вважається що значення будуть йти від нуля, в літкоді буде параметричний тест із негативним значенням обов’язково. А це вже Кент Бек — а не Дональд Кнут. Тобто спочатку аналізуємо вимоги, проектуємо — вибираємо алгоритми та API, пишемо тести і тільки після цього створюєм код. Як не дивно дуже часто це значно ефективніше за експериментальне програмування — де створили прототипа, потім запускаємо та відловлюємо і фіксимо баги циклами, доки не запрацює так як нам треба. Цей підхід часто є причиною як і повного провалу програмного проекту, так і неможливості супроводжувати (низький перформанс, неможливо легко розширювати функціонал, численні баги, неможливість переносу на інші програмно-аппаратні комлекси без суттєвої переробки тощо). Санітайзери дуже сильно корисні в цьому плані. Я використав в перше санітайзер ще 17 років тому, для свого дипломного проекту на С++ Builder і реально виявив та пофіксив декілька багів (єдине що реально зацікавило комісію в мойому проекті з 3D графіки, була маса питань як це працює). Сучасні санітайзери навіть показують помилки в дизані та ахітектурі, по зовнішнім проявам. Наприклад — довгі фінукції (15+ операторів), занадто складні оператори і оброти (по типу йлочок зі свічів чи трирівневих циклів з купою break а то і goto), занадто багато функцій в одному модулі, API із занадто складним переліком параметрів тощо. Така інформація може бути дуже корисною, крім того коли це просто блокує білд — програміст навчається, програмувати та писати більш якісний код. Досвідчених це підстраховує.
Найдорожчі помилки як відомо з самих ранні стадій SDLC (Managing Information Technology Projects Джеймса Тейлора) — у вимогах та програмно апартаментній архітектурі.
Їх станом на зараз автоматично валідувати ще не можливо. Разом з тим в цьому я якраз бачу дуже великі перспективи в AI. Принаймні мої експерименти з великими мовними моделями якраз в плані проектування та описання вимог — дуже позитивні.

Те що ви написали зветься функціональна та структурна якість програмного забезпечення.
Структурна якість відповідає різним принципам, така як здатність легко підтримувати код. Як же то так напевно стається — що якісь програмні проекти та дизайайни типу UNIX живуть десятиліттями, підтримуються розвиваються, мають масу форків : Linix, Mac OS X, FreeBSD тощо. При чому навіть коли Bell labs вже давно не те, дизайн досі розвивається різними організаціями та спеціалістами основа його та сама. А якість програмні продукти зроблені нашвидкоруч типу : DOS, Palm OS або Symbian вже не так і багато народу пам’ятає. Свого часу воно просто швидко вийшло на ринок зробило якісь гроші — а зараз викликає ностальгію і усе.

Ну успіх *nix не скільки в якості як такої, я не думаю, що там значно краще ніж в середньому по проектах, скільки в зовнішніх факторах, таких як вільна (в достатніх рамках) ліцензія, гарна сумісність з зовнішніми системами, тощо. Хоча ще і архітектурно, що трошки не рівень коду, як такого.

Гаразд що тоді не так скажімо із NASTRAN (NASA STRuctural ANalysis) ? Це якраз той самий СAE продукт який використовували для проекту «Сатурн V», тобто політу на Місяць. З рештою він змінив купу власників і тепер є NX Nastran від компанії Simens. Це був абсолютно протипаразитарний програмний продукт до 2015 року, коли його оригінальні похдні коди NASA вже в імлементації 1993 року (потім і 1995 року), не відкрили в 2015 році uk.wikipedia.org/wiki/NASTRAN як чисто музейні.
Так само по факту клонували софт вже під cучасні реалії та сучасні програмно аппратні комплекси, скажімо щоб було можливо використовувати GP GPU дуже багато компаній та організацій.

Я не розумію, до чого це

Це до базису дискусії. Програмні від початку існує два провідних підходи до розробки ПЗ. Перший — науковий тобто вірність алгоритму доказується тестуванням, та робиться початкове проектування. І експериментальний — умовно підхід великого калькулятора. (
Математично доказовий метод Едгара Дейкстери виявився не реалізовним на практиці. youtu.be/E9-scyUdmeI?t=2034 ) За SI дослідами CMM uk.wikipedia.org/...​Capability_Maturity_Model на замовлення пентагону 80% ПЗ в світі розробляється експериментальним шляхом, тобто від початку не підтримум чином і без гарантії отримання результату, може пощастить — а може ні. Пентагон є найбільшим замовником в США, хоча і має і віддає перевагу власним командам та перевіреним вендорам типу IBM.
Саме тому якість програмні продукти та архітектури розвиваються десятиліттями, деякі існують дуже не багато часу. Хоча і існує парадокс COBOL (стосується не тільки COBOL).

Було так, доки в певний момент я не почав вивчати Haskell та не зрозумів як треба, і що увесь час я просто хардкодив монади.

публиковать то надо было в пятницу )

Підписатись на коментарі