Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Ознака зменшення складності

with 12 comments

Їду в неділю в маршрутці. Читаю Макконела. Раптом розумію що хочу дещо записати, і виявляю що забув блокнот. Довелось писати на чеку, який я тримав як закладку. Виявилось все одно краще ніж в твіттері. В твіттері фіг напишеш щось таке абстрактне про програмування…

Отож, по Макконелу, основна проблема програмної інженерії – боротьба зі складністю. Складність в системі з’являється через зв’язки. Тому що зв’язки заважають відокремленому аналізу елементів. Тому, чим менше в системі зв’язків, тим вона простіша. Це очевидно.

Тепер, якщо ми замінимо слово “зв’язки” словом “залежності”, відношення про яке ми говоримо перестане виглядати симетричним. А воно і не є. Якщо A залежить від B, це ще не значить що B залежить від A.

Якщо в програмі є ще якісь зв’язки окрім залежностей – дайте приклад будь-ласка, бо я щось не можу. Наслідування, створення екземпляра, виклик функції, доступ до атрибута, передача в якості параметра – це все залежності.

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

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

А нормалізовані системи простіші за денормалізовані, бо зручно коли все в одному місці.

Ну, от так. Непогано, як для нотатки на чеку, правда?

А ще от згадав іншу аксіому. Наперед вибачте якщо для когось пишу очевидні речі. Я стараюсь робити з них очевидні висновки, які чомусь не зразу очевидні. Програма – зв’язний граф. Окрім від функції main, чи якихось інших точок входу, кожен модуль повинен мати залежні від нього. Якщо модуль не має залежних модулів, значить він непотрібний і його можна викинути. Більше того, це правило транзитивне. Якщо програма має кілька компонент зв’язності, то компоненти без точок входу можна викинути.

Увага! Під словом “модуль” тут мають на увазі частини системи на певному рівні абстракції зв’язки між якими аналізують. Звичайно на певному рівні абстракції це можуть бути модулі в класичному розумінні – окремі файли програми. Але більш точним відповідником того що я маю на увазі тут під словом модуль буде функція.

Так от, виникає потреба в інструменті який би проводив аналіз коду, і виявляв компоненти зв’язності, виявляючи код що можна видалити. Pylint поки що для цього недостатньо підходить, бо виявляє проблеми дуже локально. І динамічна природа Пітона, та метапрограмування трохи цьому заважає. Також заважають тести. Бо кожен тест має свою точку входу, тому їх не треба враховувати. Але не забувати видаляти тести модулів з непотрібних компонент зв’язності.

Можливо треба буде якось написати такий інструмент. Хіба ж не для цього створили модуль _ast? 😉

А на наступній сторінці вас чекає велика і жахлива формула.

Advertisements

Сторінки: 1 2

Written by bunyk

Квітень 24, 2012 at 04:00

Оприлюднено в Кодерство

Tagged with

Відповідей: 12

Subscribe to comments with RSS.

  1. >>>Можливо треба буде якось написати такий інструмент
    Для Visual Studio уже написали ReSharper, котрий підсвічує весь зайвий код. Перенести це на Пайтон буде .. хм.. складнувато, краще зразу переходити на C# і не паритись

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

    danbst

    Квітень 24, 2012 at 09:01

    • Переписати це на Python напевне не складніше ніж написати з нуля на C#. Хоча Microsoft круті, хто тут сперечатиметься…

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

      bunyk

      Квітень 24, 2012 at 10:07

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

      ІМХО кращий спосіб – для нового контракту написати нову версію функції і поступово її замінювати в потрібних місцях.

      bunyk

      Квітень 24, 2012 at 11:36

  2. JetBrains круті, перепрошую. Думаю в PyCharm є аналог Resharper-а. Треба буде якось таки освоїти це IDE.

    bunyk

    Квітень 24, 2012 at 11:39

  3. “Якщо в програмі є ще якісь зв’язки окрім залежностей – дайте приклад будь-ласка, бо я щось не можу.”
    Логическая связь (граф, вершина, ребро), физическая связь (функции в одном файле), причинно-следственные связи (почему так криво написан код? – в либе баг, а это – workaround). Поправь, если я неправ.

    “Якщо модуль не має залежних модулів, значить він непотрібний і його можна викинути.” – про это не понял. “Залежних” – это тех, которые зависят от него? Ну если ты пишешь прогу на c++ и юзаешь stl, то от твоего main.cpp ничего не зависит – его можно выкинуть?

    Еще можно представить ситуацию, когда некий язык X позволяет писать модули без описания зависимостей, а программист сам должен решить, какие файлы передавать компилятору и в каком порядке, чтобы все правильно сработало. Тогда как быть? К примеру, у тебя есть либа для работы с графами, либа для работы с большими числами и твоя прога, это все ты компилишь примерно так:
    megalanguagec ~/graphlib/graph.megalan ~/bignums/* main.megalan

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

    jtimv

    Квітень 25, 2012 at 21:35

    • main.cpp – це точка входу, він не рахується.

      Під модулем тут мається на увазі довільний елемент програми – файл, клас, об’єкт, метод, функція…

      Ну і будь-який dfs чи bds алгоритм готовий до того що в графі можуть бути цикли.

      bunyk

      Квітень 25, 2012 at 21:53

      • “Під модулем тут мається на увазі довільний елемент програми – файл, клас, об’єкт, метод, функція…” ??? Да ну. Отдельная инструкция тоже модулем считается? Т.е. во фрагменте int a=1; по моим прикидкам где-то 5 модулей. Не уверен, считать ли пробел за модуль – является ли он элементом программы?

        “Ну і будь-який dfs чи bds алгоритм готовий до того що в графі можуть бути цикли.”
        Конечно готовый, я не говорил, что они сломаются на цикле. Я говорил, что пользы от них будет 0, если не < 0. Кто-то напишет плохой код, ты запустишь свой инструмент, он покажет, что ВСЕ файлы от чего-то зависят (dfs нашел цикл). А на деле можно переписать код и убрать многие зависимости – но этого уже твоя прога не покажет.

        jtimv

        Травень 1, 2012 at 15:51

        • Ну невже я так незрозуміло висловлююсь?

          Фрагмент int a=1; можна розглянути як окремий модуль. Він має залежність від типу int. Від нього залежать ті модулі які використовують a. Зрозуміло що до вибору розміру модуля треба підходити прагматично, з тією метою щоб зробити аналіз системи якомога простішим. Модулі розміром з файл на мою думку завеликі, бо буває містять десятки тисяч рядків. Я знаю що в ідеалі треба обходитись сотнями рядків. Ідеальний модуль – функція що поміщається в екран. її можна проаналізувати без зайвих інструментів.

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

          bunyk

          Травень 1, 2012 at 16:11

        • Щойно знайшов шикарне визначення модуля: “A unit is the smallest testable part of an application.”

          bunyk

          Червень 5, 2012 at 09:35


Залишити відповідь

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

Лого WordPress.com

Ви коментуєте, використовуючи свій обліковий запис WordPress.com. Log Out / Змінити )

Twitter picture

Ви коментуєте, використовуючи свій обліковий запис Twitter. Log Out / Змінити )

Facebook photo

Ви коментуєте, використовуючи свій обліковий запис Facebook. Log Out / Змінити )

Google+ photo

Ви коментуєте, використовуючи свій обліковий запис Google+. Log Out / Змінити )

З’єднання з %s

%d блогерам подобається це: