О перегрузке объектов лишними сущностями

Очень часто я сталкиваюсь с подходом в программировании, который я мог бы описать как “все включено”.

Рассмотрим простой пример: некий разработчик игр, который пишет на С++, решил что STL это тормоз и вообще ужасная вещь, надо писать свой велосипед. Он сделал свои контейнеры, свои строки, все свое. Но рассказ будет не о NIH синдроме, а о том, как эти классы были спроектированы.

Возьмем его класс строки, как пример. Он умел все. Кроме базовых операций по работе со строками (сравнений и т.д.), строка умела читать себя из файла, писать себя в файл, конвертироваться во все базовые типы С++ и тому подобное. Все это помещалось в одном исходной файле размером этак под 160+ килобайт.

Это была присказка.

Так вот, на днях, один из разработчиков на нашем проекте (ASP.NET) решил сделать extension для списка строк, который бы умел сохранять и грузить его из CSV файла. В C# extension это что-то типа синтаксического сахара над существующим классом, который представляет собой функцию которую можно вызвать через объект данного класса. Для примера выше это было бы что-то типа такого:

List csv = List.LoadCSV("hello.csv");
csv.SaveCSV("hello2.csv");

Загрязнять объекты методами, которые не являются их неотъемлемой частью - это зло. Такой код потом тяжело поддерживать, классы раздуваются, теряется “идеологическая стройность” существующего кода, а так же теряется расширяемость - логика поведения таких вот утилитарных функций становится зашита в класс.

Думаете эти примеры придуманы и в реальном мире не встречаются?

Вот взять web2py, зачем делать экспорт и импорт данных в CSV частью объекта базы данных? Разве такой код сложнее написать:

export_to_csv(db, open('somefile.csv',  'wb'))

чем такой:

db.export_to_csv(open('somefile.csv',  'wb'))

Но во втором случае, идет жесткая привязка к типу объекта (база данных) и теряется reuse кода - duck typing в питоне никто не отменял.

Другой пример из того же web2py: сохранение результатов запроса как HTML! Это вообще нонсенс, включать в ORM логику представления:

rows = db(db.person.id > 0).select()
print rows.xml()

Или вот взять Руби (за пример спасибо Александру Соловьеву):

piranha@gto ~> irb
>> String.methods.length
=> 98
>> Fixnum.methods.length
=> 97
>> require 'active_support'
=> true
>> String.methods.length
=> 190
>> Fixnum.methods.length
=> 188

Зачем?

Может кто-то знает почему такое делают и почему это может быть, даже теоретически, хорошо?

blog comments powered by Disqus