Закрыть
Авторизоваться через пароль



Забыли пароль?
Авторизоваться через OpenID

 

Monkey patching как инструмент партизанского программирования

злой абизянВ некоторых языках программирования (Python, Ruby, JavaScript и некоторые другие) есть возможность переопределять атрибуты и методы классов во время исполнения программы. На этой возможности была построена целая техника программирования, она называется Monkey Patching.

Откуда взялось такое название?

Изначально термин назывался guerilla patch (партизанский патч): разработчик незаметно добирался до чужого кода, изменял на лету поведение этого кода, не заботясь о соблюдении каких-либо правил, установленных создателем, а потом так же незаметно исчезал, оставив создателю порцию говна, в виде кода не работающего, как надо, без видимых на то причин. Поскольку, слова Guerilla и Gorilla звучат очень похоже — вскоре эту технику стали называть «горилла патч», что в конце концов трансформировалось в monkey patch. Именно этот термин прижился, поскольку лишен негативной окраски предшественников.

Практическое применение

Думаю, главное практическое применение техники обезьяних патчей — расширение функционала чужих продуктов (фреймворков, библиотек) без непосредственного вмешательства в их код, а также, т.н. security patches. Хотя, как инструмент террора, эта техника не менее хороша.

Пример из жизни

Существует замечательный, но не лишенный недостатков, фреймворк для веб-приложений — Django. В нем уже существует модель пользователя (User), используемая для авторизации, разграничения прав доступ, хранения самих пользователей… Естественно, эту модель нужно использовать. На практике оказывается, что у пользователя могут быть дополнительные атрибуты (не предусмотренные фреймворком), например, пол или телефон. Первое, что хочет сделать здравомыслящий разработчик, — написать новый класс пользователя, унаследовав его от джанговского. Увы, один из главных минусов django — его ORM не поддерживает наследование моделей, то есть модель то создастся… но она всего лишь продублирует все поля родителя в новую таблицу базы данных, создав тем самым избыточность.
В нашем случае можно сделать дополнительный класс UserProfile для дополнительных полей и связать его с классом User отношением один-к-одном,. но признайтесь, это, явно, не самое красивое решение, тем более, когда-нибудь в django доработают ORM. Патчить исходные коды django — вариант еще хуже, так как все нормальные разработчики пользуются его версией из репозитория (SVN), которая обновляется почти каждый день… выход один — monkey patching!
В любом файле (желательно в моделях) пишем слудующее:

from django.contrib.auth.models import User

GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
)
User.add_to_class('gender', models.CharField(max_length=1, choices=GENDER_CHOICES))
#Вцелом, этого уже достаточно, но для самой админки django добавим следующее:
User._meta.admin.fields += (
('Additional', {'fields': ('gender',)}),
)
User._meta.admin.list_display = User._meta.admin.list_display + ('gender', )

Все, отныне, никаких бесполых пользователей!Точно так же можно расширять функционал встроенного в django модуля FlatPages, представляющего из себя простейшую CMS-систему и многое-многое другое.

Меры предосторожности

Не стоит забывать, что monkey patching — это именно хак, а не нормальное поведение программы и применять его стоит только в тех случаях, когда иначе ситуацию решить нельзя. Будьте уверены, если такой патч, в будущем, вызовет ошибки в коде — наверняка, после многочасовых поисков причины, кто-нибудь захочет вас больно побить. Избежать этого довольно просто: всякий раз, когда применяете monkey patching, заботьтесь о том, чтобы этот код был покрыт автоматическими тестами.

Комментарии

cencio 15.02.2008
avatar

знаковый способ, пару дней назад им “поправили” один майкрософтофский аджакс контрол, котоый айтемы в контекстном меню всегда открывал в новом окне, а не так как от нас по спеке требовали

Ответить

Скакунов Александр 15.02.2008
avatar

Интересно. Не слышал про такое. А аватар Роберта хорош :)

Ответить


zgollum 15.02.2008
avatar

Насколько я понял, в джанге есть механизм привязывания к пользователю (к модели User) дополнительной модели профиля, которая уже может содержать все, что тебе угодно. Делается это на уровне settings.

Ответить

Glader 15.02.2008
avatar

Не, лучше так не делать :)

Ответить


Andrewsk 15.02.2008
avatar

С профайлом много гемора. Основной недостаток - на select_related ORM не вытягивает профайлы, получается, что нужно делать финт ушами, чтобы вытянуть всю дополнительную информацию по профайлам за один запрос. Monkey patching - элегантнее получается.

Ответить

Стас Давыдов 4.03.2008
avatar

Возможно, это решение слишком очевидное, чтобы его использовать, однако, на деле, оно обычно экономит тучу времени.

Почему бы просто не послать нафиг фреймворки?

Ответить

Uznick 11.03.2008
avatar

Вцелом, этого уже достаточно, но для самой админки django добавим

Не достаточно, к сожалению. Если этого не добавить вылезает ворнинг “Column was set to data type implicit default; NULL supplied for NOT NULL column ‘новое_поле’ at row 1”

А с ними вылезает ворнинг Data truncated for column ‘change_message’ at row 1 :(

Ответить


Comment form for «Monkey patching как инструмент партизанского программирования»

(Required. 30 chars of fewer.)

(Required.)



(Пожалуйста, введите слово, которые вы видите на картинке)
captcha image