Monthly Archives: Квітень 2012

Про конкуренцію в програмістів

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

Якось на зустрічі з приводу десятиріччя вікіпедії я спілкувався з російським вікіпедистом (який жив в Києві достатньо довго щоб мене розуміти). Він фінансист з System Capital Management, чи щось в тому роді, точно не пам’ятаю. Так от він сказав, що по своїй спеціальності в вікіпедію не пише, щоб не допомагати конкурентам. Пише про цікаві місця Києва, для розваги. Мені було дивно що в мене прямо протилежні бажання. З мого блогу видно, що я всіма силами намагаюсь допомогти конкурентам.

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

З іншого боку програмісту самому вигідно допомагати іншим, бо це збільшує досвід, дозволяє отримати конструктивну критику без якої вдосконалюватись важко, і найголовніше – збільшує вплив. Якщо я відкрито продемонструю всім можливість писати крутіше ніж Роман Хоменко, то після того як всі про це дізнаються, приїду в Харків, і заміню його на його роботі :) .

Хоча насправді коли таке відбувається… А ніколи, тому що всі програмісти різні, і кожен майстер у своєму проекті. Вони від відсутності конкуренції навіть придумали спортивне програмування, де всі програмісти пишуть один і той самий проект. Ізольовано. Для розваги. Проект зазвичай не має жодної практичної цінності. І кожен контест для суспільства – це втрата кількох сотень дуже дорогих (за собівартістю і ринково) людино-годин.

Яким чином ведення блогу покращує конкретно мою позицію на ринку праці? З двох сторін.

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

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

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


Filed under: Кодерство, Психософія Tagged: розробка

Про конкуренцію в програмістів

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

Якось на зустрічі з приводу десятиріччя вікіпедії я спілкувався з російським вікіпедистом (який жив в Києві достатньо довго щоб мене розуміти). Він фінансист з System Capital Management, чи щось в тому роді, точно не пам’ятаю. Так от він сказав, що по своїй спеціальності в вікіпедію не пише, щоб не допомагати конкурентам. Пише про цікаві місця Києва, для розваги. Мені було дивно що в мене прямо протилежні бажання. З мого блогу видно, що я всіма силами намагаюсь допомогти конкурентам.

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

З іншого боку програмісту самому вигідно допомагати іншим, бо це збільшує досвід, дозволяє отримати конструктивну критику без якої вдосконалюватись важко, і найголовніше – збільшує вплив. Якщо я відкрито продемонструю всім можливість писати крутіше ніж Роман Хоменко, то після того як всі про це дізнаються, приїду в Харків, і заміню його на його роботі :) .

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

Яким чином ведення блогу покращує конкретно мою позицію на ринку праці? З двох сторін.

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

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

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


Filed under: Кодерство, Психософія Tagged: розробка

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

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

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

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

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

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

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

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

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

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

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

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

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

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


Filed under: Кодерство Tagged: розробка

Інтроспектор: “Хто присвоїв атрибуту це значення?”

Ану признавайтесь падлюки! :)

Іноді в процесі зневадження з’являється питання “Хто й коли присвоює цьому атрибуту неправильне значення?”. Покрокове проходження через тисячі рядків коду нудно і занадто складно. Що робити?

Елементарно, Ватсон! В Python надзвичайна здатність до інтроспекції.

Візьмімо для прикладу таку програму:

from watch_attribute import watched_attribute
import random

def change_here(x):
    x.x = random.random()

class Foo(object):
    add_watched_attribute('x')

foo = Foo()
foo.x = 2

for i in range(2):
    foo.x = foo.x * 2
    change_here(foo)

y = foo.x

Програма притягнута за вуха, суто щоб потестувати watched_attribute – функцію недавно написана мною, яка змушує атрибут доповідати про всі дії які з ним роблять. Результат роботи програми виглядає наприклад так:

/home/bunyk/progs/test_watch_attribute.py:13 foo.x = 2
x set to 2
/home/bunyk/progs/test_watch_attribute.py:16     foo.x = foo.x * 2
x is 2
/home/bunyk/progs/test_watch_attribute.py:16     foo.x = foo.x * 2
x set to 4
/home/bunyk/progs/test_watch_attribute.py:7     x.x = random.random()
x set to 0.288351784619
/home/bunyk/progs/test_watch_attribute.py:16     foo.x = foo.x * 2
x is 0.288351784619
/home/bunyk/progs/test_watch_attribute.py:16     foo.x = foo.x * 2
x set to 0.576703569239
/home/bunyk/progs/test_watch_attribute.py:7     x.x = random.random()
x set to 0.300510362936
/home/bunyk/progs/test_watch_attribute.py:19 y = foo.x
x is 0.300510362936

З прикладу незрозуміло нащо це треба, тому я покажу як я використав це на роботі. Отак:

('uaprom/forms/wt_fields.py', 1583) 'sets data to' 90000L
('wtforms/form.py', 133) 'gets data' 90000L
('wtforms/form.py', 133) 'gets data' 90000L
('uaprom/forms/wt_fields.py', 1583) 'sets data to' 90000L
('uaprom/forms/wt_fields.py', 1596) 'sets data to' 501L
('uaprom/forms/wt_fields.py', 1634) 'gets data' 501L
('uaprom/forms/wt_fields.py', 1635) 'gets data' 501L
('uaprom/forms/wt_fields.py', 1635) 'sets data to' 9018.0
('uaprom/forms/wt_forms.py', 931) 'gets data' 9018.0
('uaprom/forms/wt_validators.py', 721) 'gets data' 9018.0
('uaprom/forms/wt_validators.py', 722) 'gets data' 9018.0
('uaprom/forms/wt_validators.py', 722) 'sets data to' 501.0 <-- от хто винен!
('wtforms/validators.py', 150) 'gets data' 501.0
('uaprom/forms/wt_fields.py', 1629) 'gets data' 501.0

Звичайно треба ламати руки тому хто змінює значення полів в валідаторах, але я живим не дамся! Приклад нам показує що коли атрибут читають і пишуть 14 разів в 5 різних файлах, то перечитування коду чи навіть трасування програми не допоможе знайти проблему так швидко як такий лог. Бо поки залізеш в один файл, розпечатаєш там значення, поки в інший…

Ну, а зараз час подарувати вам код модуля watched_attribute:

import sys
import inspect

def from_where_called():
    info = inspect.getframeinfo(sys._getframe(2))
    # інформація про фрейм на два вище за поточний
    # (функція яка викликала функцію що викликала оцю функцію)
    code = info.code_context[0] if info.code_context else ''
    return '%s:%s %s' % (info.filename, info.lineno, code)

def add_watched_attribute(name):  
    def attr_watch_get(self):
        value = getattr(self, '_' + name, 'unset')
        print from_where_called(), name, 'is', value
        return value

    def attr_watch_set(self, value):
        print from_where_called(), name, 'set to', value
        setattr(self, '_' + name, value)

    sys._getframe(1).f_locals[name] = property(attr_watch_get, attr_watch_set)

Від чого я в цьому коді прусь, так це від того, що getter і setter для property сховані в замиканні, і не засмічують простір імен класу. А тепер також від того, що функція виявляється має доступ на запис, до простору імен на рівень вище (останній рядок). Ну хіба це не прекрасно?


Filed under: Кодерство Tagged: зневадження, Python

Додзьо для регулярного ніндзя

Щойно вивчив чим відрізняється negative lookbehing від negative lookahead.

Шукав всі пітонівські файли які не є скомпільованими мако файлами що містять певний шаблон. В моєму випадку – всі місця в проекті, в яких рендериться вміст листів. Написав:

    :Ack -G "(?!\.mako)\.py$" "email/[_/\w\d]+\.mako"

Не знайшов. Бачите в чому помилка? Тут я використав lookahead, а треба було lookbehind. Lookbehind пишеться так:

    :Ack -G "(?<!\.mako)\.py$" "email/[_/\w\d]+\.mako"

Хто б подумав, що треба писати так. Але тепер я вже знаю :) . Ах, для тих хто не зрозумів що відбувається, ack – це типу grep.

І от в мене виникла ідея – взяти якось на вихідних і написати інтерактивний підручник регулярних виразів. Такий собі html-файлик, всередині якого в JSON записано набір уроків в такому форматі:

[
    {
        'Назва': "...",
        'Текст уроку': "...",
        'Вправи': [
            {
                'Умова': "...",
                'Корпус тексту': "...",
                'Тип вправи': 1, # пошук/заміна
                'Підрядки що потрібно отримати з домогою виразу': ["...", ...],  # якщо пошук
                'Текст що потрібно отримати в результаті': "...", # якщо заміна
                'Бали': XP, 
            },
            ...
        ]
    },
    ...
]

І тебе пускають до наступного коли ти набрав необхідну кількість балів на попередньому.

Тепер розшукую regexp – гуру, jQuery – гуру, гуру верстки, і технічних письменників (чи просто літературних редакторів) які б це все допомогли реалізувати.


Filed under: Кодерство, Павутина, Розмітка Tagged: JavaScript, розробка, цілі