Комментарии 148
Спасибо за перевод.
Кейсов описаных в посте у меня не было — чаще всего у меня классы пустышки — это дети родителей которые не имеют своего поведения — то есть с точки зрения програмной логики они сейчас не нужны, но по бизнес-логике это отдельные сущности которые потенциально могут обрабатываться иначе.
То есть скажем в данном примере (если я правильно понял) ячейка может иметь только значение да\нет поэтому вся полезная инфа в ней в том что такие-то координаты в сетке заняты живой клеткой. А если «внезапно» окажется что у клетки может быть 4 состояния — придется всётаки создавать класс. А так бы он хоть примитивный но был уже.
Ещё раз: во многом вопрос вкуса но из проблем мешающих читаемости кода для меня маленькие классы меня напрягают очень и очень мало.
Где, простите?
Пример из кучи классов и 660 строк оторван от жизни. Обычно классы с одним единственным методом создаются ради шаблона чёрного ящика.
На самом деле применение ООП довольно неплохо в тех архитектурных решениях, когда проект прозрачен на самом первоначальном этапе его написания. То есть сразу понятны основные объекты или в том случае, когда руководитель программист и понимает что куда сувать в дальнейшем и сколько времени можно потратить на рефакторинг.
Но суровая практика показывает, что «игроки в гольф», как именуют менеджеров высшего звена за пару месяцев могут превратить любую изначальную идею в стройную кашу, хаотичную разработку. Причём не от глупости, как часто считают программеры, а от степени осознавания проекта, когда сакми уже начинают осознавать что получилось или по отзывам клиентов. ООП предназначался скорее для джедаев, сверхмозгов, которыми считали программистов. Редкий программист способен предугадать истинное развитие проекта на практике, мы же тоже люди.
Достаточно часто частные решения «банды четырёх» спасают, как самостоятельные решения внутри любого не ООП кода в частности, proxy. А в общем, поосторожнее надо с чистым ООП, пустое это.
Ну что, попробуете доказать, что ваша аналогия лучше моей?
bakaneko, никто никуда не проваливался.
Хабралюди, ставьте минусы, но когда-нибудь придумают то, что круче ООП
и ничего, вроде до сих пор считают и ещё хрен знает сколько будут считать
Ну для простых людям что там вокруг чего вращается неважно, а специалистам неплохо бы знать, что утверждение "Земля вращается вокруг Солнца" неверно.
Специалистам неплохо бы знать, что верность утверждений "Земля вращается вокруг Солнца" или "Солнце вращается вокруг Земли" зависит лишь от выбранной точки отсчёта. Гелиоцентрическая модель Солнечной системы в которой планеты, включая Землю лишь более простая и, что ли, элегантная. А для практических задач нужно выбирать ту, которая обеспечит оптимальное для задачи соотношение вычилительной сложности и точности. Для каких-то задач типа пилотирования КК может оказаться, что лучше использовать модель с совершенно другой точкой отсчёта, например, центром масс самого КК.
Только что-то мне подсказывает, что ключевую мысль можно выразить короче ;-)
def greeter(greet):
return lambda name: "%s, %s" % (greet, name)
Всяко короче и проще, чем у него.
import functools
greet = functools.partial(greet, 'превед')
greet('красавчик')
Я понял :)
greeter('превед')('кросавчег')
import functools
functools.partial(greeter, 'превед')('красавчик')
Я так, чисто на всякий случай напомню, что изначальная задача была — иметь по сути шаблонную функцию с заданными свойствами (hello). Автор ломает этот функционал, и говорит нам: «Нет, у вас будет просто функция без свойств. Если вам очень хочется, используйте functools, которые в общем-то инкапсулируют эту функцию в объект-функтор». То есть, сделает ещё более сложную иерархию, чем была сначала. Это — упрощение? Это — борьба с классами?
greet('A', 'B')
и для множественного:
g = partial(greet, 'A')
g('B')
g('C')
g('D')
Если задаться целью сделать функцию со свойством, это возможно (кстати, можно же аттрибут функции записать!), но тогда она будет работать только по одному шаблону, по множественному. Для разового вызова она неудобна.
Насколько хорошо каррирование в Питоне (он, кстати, автор .partial) судить не могу.
Более того, если бы вдруг захотелось где-то поиспользовать одиночные вызовы, то, даю слово, здесь это тоже можно было бы реализовать:
def pgreeter(a, b):
return greeter(a)(b)
На всё про всё 4 строчки, никаких дополнительных импортов, никаких классов, который ненавидит, но использует автор.
Кстати, он не ненавидит классы. Он говорит прямо и приводит пример с heapq, где класс как раз нужен. Просто классами часто злоупотребляют.
Я б сейчас это всё переписал, потому что соль его заявлений — в середине. Но уже из песни слов не выкинешь.
greeter = lambda greet: return lambda name: "%s, %s" % (greet, name)
И для любителей сокращений как в математике
r = lambda g: return lambda n: "%s, %s" % (g, n)
Декомпозиция временами требует таких вещей, но всегда нужно соблюдать баланс.
Иногда бывает видишь код и думаешь — нафига все это, тут же все в две строчки можно.
А иногда видишь две строчки и рвешь волосы, т. к. эти из-за этих двух строчек в большой системе, придется очень много всего переделать для внесения нового функционала.
По моему, главное: «Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете».
«Сделать HTTP запрос» это не объект, а вот Board и Cell вполне себе объекты. И по мере того, как они используются в программе, могут добавляться различные их разновидности (подклассы), и исходный класс может делегировать часть логики из методов neigbors/advance в подклассы прозрачно для пользователя…
Например, если нам надо поддерживать 2 вида клеток: 1) которые считают соседями клетки сверху-снизу; 2) которые считают соседями все клетки, включая диагонали.
С классом Cell метод neigbors переопределяется на раз без изменения API, с отдельным же методом neigbors надо менять API и способ вызова. А рефакторинг в большой системе на питоне еще то удовольствие…
Нужно просто понимать когда нужен класс, а когда функция.
без изменения клиентского кода?
> Нужно просто понимать когда нужен класс, а когда функция.
это не так «просто», как показывает данный пример…
в пробном проекте для себя любимого, neighbors может быть и функцией, а вот если это долгий проект, требования могут меняться, етк, то лучше сразу сделать класс.
Это как раз и мастерство: знать, когда можно «срезать углы» и обойтись функцией, а когда надо и «соломки подстелить» и добавить возможность расширения…
Если вы видите класс с двумя методами, включая __init__, это не класс.
К этому:
На этом месте надо сказать «стоп»: у нас есть класс Поле, в котором 2 метода: __init__ и «сделать ход». В нём одно свойство — словарь, значит со словарём и надо работать. Заметьте, что не надо хранить соседей точки, они уже и так есть в словаре. Живая точка или нет — это просто булевое значение, поэтому будем хранить координаты только живых клеток. А раз в словаре хранятся только True, нужен не словарь а просто множество (set) координат. Наконец, новое состояние не нужно, можно просто заново создать список живых клеток.
… дорога лет в 10 для среднестатистического человека. Я лично уже наверное никогда не дойду.
1. убираем класс
2. смотрим, что в словаре True и False, и нам нужны только True, следовательно убираем False
3. понимаем, что словарь только из True бессмысленен, заменяем на set.
import itertools
def neighbors(point):
x, y = point
for i, j in itertools.product(range(-1, 2), repeat=2):
if any((i, j)):
yield (x + i, y + j)
def advance(board):
newstate = set()
recalc = set(itertools.chain(*map(neighbors, board)))
for point in recalc:
count = sum((neigh in board)
for neigh in neighbors(point))
if count == 3 or (count == 2 and point in board):
newstate.add(point)
return newstate
glider = set([(0, 0), (1, 0), (2, 0), (0, 1), (1, 2)])
for i in range(10):
glider = advance(glider)
print glider
Приведенный пример с игрой «Жизнь» очень характерен. Да, в виде такого вот отдельного примерчика все выглядит замечательно. Но если представить себе, что это — кусок настоящего серьезного проекта, то дальше последует классическое:
— Теперь нам надо вариант «Жизни» с 4 цветами, по поколениям;
— Состояние игры надо сохранять…
— … в XML…
— А теперь пусть будет вариант в котором есть 8 полей рядом и на каждом игра идет по своим правилам
— И вообще надо сделать поле с шестиугольными ячейками.
Так вот, грамотно сделанные классы дают нужную гибкость и расширяемость. А вот предложенное «элегантное решение» нужно будет рефакторить, преобразовывать в классы — и хорошо, если рядом будет более опытный разработчик, который заставит это сделать сразу. Иначе получатся такие спагетти, что мама не горюй…
Ничего не мешает комбинировать функциональный подход с ООП, практически все промышленные языки это позволяют.
Классами баловаться нужно до известного предела. Пикселы (в игре жизнь тоже) или биты в строковых выражениях — классический пример, когда накладные расходы выше чем польза.
С другой стороны в некоторых задачах объектный подход — это как глоток чистого воздуха, когда у тебя реальные объекты (а не абстракции N-ного уровня), они есть и все тут.
В оторванном от контекста примере — да. А если эта «жизнь» будет на самом деле библиотекой, которую будет использовать куча народа и каждый третий будет просить её немножко допилить? Про это ключевой разрабочик питона ничего не написал?
"… те сущности, которые являются объектами, лучше объектами и оставить. «Сделать HTTP запрос» это не объект, а вот Board и Cell вполне себе объекты. "
Если вы с этим не согласны, аргументируйте плиз. Заодно со ссылкой на «библиотеку гугла», где функциональность, эквивалентная классовым методам, вынесена в отдельные функции.
Могу привести пример из текущего проекта. Я тренирую классификаторы. Они вызываются одной функцией. Чтобы подключить их мне бы хватило пары строк кода. Но у босса были далекоидущие планы, и это все было обернуто в систему плагинов. +500 строк кода. Планы не оправдались. Но теперь, чтобы подключить его и отладить работу — мне нужен целый день. Вместо пяти минут.
Классы — это не всегда плохо. Необоснованная сложность — это плохо всегда.
Абсолютно согласен, осталось немного: понять когда сложность «необоснованная» :)
Класс вместо функции в учебном примере — необоснован.
Система плагинов вместо 3х строчек кода/простой фабрики — необоснована.
Классы Board/Cell в реальной библиотеке для игры «Жизнь» — мне кажутся обоснованными.
>> import life
>> b = life.simulate(a, 1)
a, b — двумерные массивы интов или булианов. a — исходное поле, b — после симуляции за 1 шаг. simulate — функция, которая бы обсчитала поле N шагов.
Все предельно ясно. Не нужно описывать поле десятью параметрами, не нужно задавать методы для клетки, отдельные свойтва для проверки — есть значение, нет значения — зачем?
2)Это лучше чем заказчик платил за четырехугольники, нужны им шестиугольники, а программисты сделали квадраты потому что так классов меньше.
Да, код который гонят потоком менее элегантен и выверен чем штучный.
Это происходит в том числе потому программисты часто не знают бизнеса заказчика (в отличии от данного кейса) и такие вещи как «тут нафиг не надо было этого городить» выясняются под конец только.
Это плохо что программисты заранее не обладают четким представлением о том что нужно (и может стать нужным) заказчику в будущем.
Но при балансе между «написать лишний класс» и «соптимизировать лишний класс» я в большинстве случаев выберу первый кейс потому что если есть сомнения значит лучше перебдеть чем недобдеть.
2) Если заказчик платит за простое решение, а хочет сложное — это обман испонителя.
Вот с этим
В той было 660 строк, в этой — 15. Всё, что делает этот код — пользуется методами стандартной библиотеки.
я согласен — выпендриваться и создавать свой URL или String с блекджеком не имея понятия зачем это нужно не стоит.
Однако в случае когда у нас есть бизнес-сущность «ячейка» и «доска» их стоит создать даже если они будут делегировать всё банальному boolean и boolean[][] соответственно потому что мне проще понимать программу находясь на уровне абстракции который скрывает от меня примитивные типы.
2) Если заказчик платит за простое решение, а хочет сложное — это обман испонителя.
я не настолько высоко сижу чтоб меня волновало выбивание денег из заказчика, пока в случае CR заказчик платит. Но лучше когда простое с т.з. заказчика изменения является таким и для разработчика.
Могу подписаться под каждым словом. По моему опыту, все еще гораздо хуже. Как будто у программистов психологический дискомфорт, если в коде нет класса. Думается, ООП лучше учить после двух-трех лет процедурного или функционального программирования. Чтобы гвозди в мозг загонялись постепенно, и инструмент не превращался в религию.
Для такого первичного обучения js отлично подошел бы (если бы не гемморойный scope и убогая работа с массивами)
А вообще я сам свидетель того как у одного нашего сотрудника, который ну просто очень любит писать классы (PHP), доходило до того, что какой-то один класс состоит из двух методов. Вот я задал ему вопрос, а нафига? Можно же написать 2 функции и не делать мозги с классами. На что получил ответ: «Мне так удобнее».
Вопрос в чем содержится структура проекта?
Если она сосредоточена в классах и шаблонах, как это обычно бывает в C++ и Java, то делать отдельную определенную функцию по меньшей мере странно (за это в приличной команде и побить могут). Как ее вписать в общую структуру? И в этом случае класс с одной функцией может быть лучшим решением.
Парадигма ООП провалилась. Нет. Она просто достигла границ применения. Строить большие библиотеки для создания интерфейсов удобнее в рамках ООП.
Основной посыл статьи это, по сути, призыв к бритве Оккама. То, что не несет смысловой нагрузки, должно быть исключено из идеального кода.
PS: Я лично часто встречался с тем, что классы используют только для изоляции кода. Это плохо, ибо это не функция класса, это функция namespace, внедрить которую можно в любой момент даже после разработки кода.
Пример, допустим генерация таблицы с клиентами и ещё парой параметров для них. Используется 1 раз во всё проекте, писать для этого класс чисто под этот функционал, ИМХО, немного расточительно.
Но если работает, то зачем дёргать человека, чтобы переделал скрипт с учётом моих прибабахов?) Вот я и не трогаю)
Однако с ростом объемов проекта эти затраты (на создание классов) пропорционально уменьшаются и на первый план выходят другие — уже упоминавшийся выше God object например. Я видел классы с более чем десятком тысяч строк кода и когда видишь такое понимаеш что лучше бы авторы придумали как разбить этот класс на десяток других, поменьше.
Простое лучше сложного;
Плоское лучше вложенного;
Важна читаемость;
Если программу трудно объяснить, она плохая.
Плюс, лично у меня, как PHP-программиста есть трудность в переключении контекста — обычно с функциями используются простые переменные ($x = sqrt($y)), а объекты чаще всего взаимодействуют с объектами, поэтому код $userChoice = prj_user_choice([User ]$user) будет выглядеть несколько обманчиво — подсознательно от функции я ожидаю простую переменную. Со статическими методами проще, название класса настраивает на то, что метод скорее всего вернёт связанную с этим классом информацию. И, кстати, интересное наблюдение — функция, возвращающая объект — необычно; метод, возвращающий простую переменную (число, например) — ок.
Даже если делаешь маленькую утилиту, гораздо лучше сделать класс с 5 статическими методами, чем свалку из функций и глобальных переменных. Хотя бы из соображений повторного использования кода.
По моим наблюдениям, презрительно отзываются об инкапсуляции, ООП, уменьшении связности кода обычно те, кто в жизни не делал ничего больше сайта из нескольких разделов. Или скрипта на костылях для пережатия картинок. Или которые копипастят код из проекта в проект, меняя там пару строчек. Или кто так и не понял, зачем вообще были придуманы классы и объекты. Или делают помойку на хуках и функциях (в плане качества кода) типа Друпала.
Конечно, есть немало примеров оверинжиниринга, когда ради 2 простых действий используется куча геттеров, сеттеров, наследование, абстрактные интерфейсы и фабрика отдельным классом. Или ради сложения дат делают отдельный класс. Но разве это говорит о недостатках ООП подхода? Нет.
Использование Ооп никак не противоречи KISS, DRY и подобным рекомендациям.
Давайте возьмем любой проект, над которым работает хотя бы человек 5, или в котором планируется большрой объем фнукционала, и посмотрим, с какой скоростью как у них будут при таком «первобытном» подходе появляться конфликты имен, дублирование кода, лапша и баги. Ваши костыли не масштабируются. День школоты на Хабре, блин.
C восторгом про ООП обычно отзываются те, кто его не так давно познал (=2-4 года с ООП, из них год-другой с паттернами), и при этом всякие SCIP не читал. Есть, конечно, другая крайность — люди, которые пописали с классами-паттренами что-то java-подобное лет 5-10, потом только вот прочитали SCIP и «прозрели», тут все вообще на функциях переписывать начинают, с map/reduce/curry/рекурсией где нужно и где ненужно. Возможно, потом этап «по дефолту — функции, если где-то это жмет — класс» наступает. Но я лично без понятия, как правильней и лучше всего) imho оно и есть imho
В питоне нормальные неймспейсы и система импортов, статические методы классов поэтому там редко когда нужны.
термин «статический метод» из ООП — это самостоятельная штука, которая ортогональна и неймспейсам, и модулям. в подмене одного понятия на другие нет причинно-следственной связи — они все абсолютно нормальные, в своих понятийных областях. ООП предлагает чёткий логический фреймворк для структурирования кода, и к каким последствиям приведёт такое замещение, предсказать сложно.
думаю, хорошим контр-примером здесь служит Django, которая очень активно пытается использовать систему питонячих модулей, для структурирования ООП-кода, и каким заморочкам это приводит на практике. мм. т.е. известно к каким — при таком подходе к зависимостям от интерфейса, добавляются зависимости от неймспейса (читай — конкретных библиотек) — в результате чего код намертво привязывается к конкретной реализации.
Про статические методы — немного схитрил, т.к. в питоне есть staticmethod, который внутри вызывать другие статические методы может только явно указывая текущий класс — опять привязываясь к конкретной реализации. classmethod имеет больше смысла, а то и нормальный метод.
Другое дело, что часто даже для несвязанных друг с другом функций классы используются в качестве неймспейсов, для таксономии, организации кода. Вот в этом смысла вроде нет (я по крайней мере, придумать его не могу — может знаешь?), и вот тут питоньи неймспейсы делают то же самое, только проще. Т.е. классы, как мне кажется, лучше использовать, когда они дают какие-то конкретные преимущества, а не «по умолчанию» просто для организации кода.
Давайте возьмем любой проект, над которым работает хотя бы человек 5, или в котором планируется большрой объем фнукционала, и посмотрим, с какой скоростью как у них будут при таком «первобытном» подходе появляться конфликты имен, дублирование кода, лапша и баги
Использование статических методов класса там, где требуется обычный namespace — это и есть всовывание ООП куда не надо. Именно об этом и была статья.
Автор статьи видимо не в курсе существования статических методов класса? Лучше свалить в глобальное пространство имен все функции скопом?
Вы так говорите, как будто только две альтернативы.
Объектно ориентированное программирование — это мышление объектами. Представляем себе объекты реального мира и манипулируем ими в своей программе. Вместо того, чтобы передавать айдишники — передаём объекты и т.п.
Где-то читал, что когда ООП появилось — многие говорили, что это лишняя надстройка и всё можно сделать функциями. Но это совсем не так — это другой подход, и синтаксис тут не причём.
В языке TCL до того, как появилась там нормальная поддержка ООП — люди умудрялись функциями программировать объектно.
О проектировании иерархии классов говорили все, кому не лень — одни по делу, другие болтали «об имитации объектов реального мира».Jeff Alger, «C++ for real programmers»
Например, работая сайтом — сложно представить где там объекты, как их использовать, и зачем вообще нужны эти классы.
А вот когда пишешь игру какую-нибудь? Например, мортал комбат :) здесь сразу понятно — объект — персонаж, у него руки — объекты, ноги — объекты, пальцы — также объекты :) Этакая получается композиция из объектов.
Теперь снова возьмём сайт. Допустим — он доставляет посылки из одной страны в другую. У нас такие объекты:
Страна
Посылка
Склад
У посылки можно выделить метод getCountry() — вернёт объект страны, в которой теперь сейчас посылка. Или сложнее — у посылки вызвать getWarehouse() — вернёт объект склада, а у объекта склада можно сделать getCountry(). Потом чтобы послать посылку можно вызвать метод sendToCountry и передать ему страну назначения. При желании, можно даже взвесить посылку :)
Я сам втыкал в ООП довольно долго и был одним из тех, кто также не мог понять чем классы всё-таки отличаются от функций. В итоге, наверное, яваскрипт помог — когда видишь на экране эти самые объекты, которые двигаешь и т.п.
Python назван так в честь крутых британских комиков — Monty Python, а не в честь змеи. Так что на русском правильнее писать Пайтон, так как именно так читается название оригинального скетч-шоу. Извините за занудство.
Автор берет неудачный ООП-API, или просто неудачный пример использования ООП, и выставляет это как недостаток всего подхода. WTF? И да, не нужно про «ООП головного мозга» тут, я прекрасно понимаю, что есть место и ООП, и функциональным языкам, и процедурным, и так далее. Просто для каждой задачи — свой «tool». Не нужно говорить, что космический корабль не решает своей задачи, заставив его рыть землю. Не нужно человеку, потерявшемуся на 2 дня в пустыне и только вернувшемуся, протягивать печенье. Не нужно применять ООП там, где очевидно требуется функциональный подход.
> «Я не против классов в принципе. Классы бывают нужны — когда много меняющихся данных и связанных с ними функций.»
Ну очень спорное заявление от всемогущего суперумного чувака. Класс нужен там, где есть «состояние» данных (некий state), которое нужно хранить, контролировать life-time, соблюдать инкапсуляцию.
Плюс методы проще тестировать, вернее стабать и мокать их. Правда в python может и не так, я со своей колокольни смотрю.
Если же есть объект с методами и состоянием, легко завязать его методы на состояние, легче появляются неявные связи и зависимости между методами, сложнее понимать, как что работает (т.к. чтоб понять, как работает метод, недостаточно посмотреть в этот метод, нужно еще понимать, откуда берется состояние — а оно, возможно, суперклассом вычисляется или еще где-то, даже в сам класс посмотреть недостаточно бывает, чтоб понять, как работает какая-то его часть).
Про стабать и мокать — в питоне это совершенно без разницы, что функцию, что метод мокать. К тому же с функциями стабать и мокать нужно при тестах реже, т.к. связность кода меньше.
У классов есть преимущества — например, более удобный синтаксис для переопределения какой-то одной части вычислений при сложном взаимодействии (через наследование), или более удобный/привычный синтаксис, когда состояние все-таки есть, оно неизбежно и с ним нужно работать как-то. Короче, баланс какой-то искать всегда лучше — но плюсов у функций много.
У Гугла же я вообще наблюдаю деградацию решений и API, ну тот же android и wp7 сравнить, в wp7 все раза в полтора компактнее. Да, есть некий стереотип google = лучшие кодеры, но у меня есть подозрения что лучшие кодеры у них со временем будут просто сидеть, смотреть по сторонам и перманентно о… ть.
Вот только тесты в это «как проще» не вошли.
Вот только проект «пошёл» и стал бурно расти и расширяться во всех местах. Даже там, где и в голову раньше бы не пришло.
Вот только функции, которые делались как проще, а значит с нерасширяемыми сигнатурами, без объектов и т.п. вросли везде в логику.
А так как тестов не было, да и времени тоже, то и рефакторинга по сути тоже не было, и расширяли как получалось, часто совсем корявыми костылями, вроде глобальной переменной, которая меняла поведение, каких-то функций там в глубине (вздрогнули?).
Короче ппц пришёл проекту, кризис, сто потов сойдёт пока фичу добавишь. В одном месте починишь, в другом ломается. Иногда девелопер говорит «да вы чего, ребята, сами подумайте, как я мог там сломать?», а через час с круглыми глазами «мда ...». Клиенты в шоке, продажники тоже. Переписывать дофига, а рынок не ждёт, но всё же собираются. Кадровые перестановки. Код из «локаничного» превратился в неудобоворимую лапшу.
Поэтому ярых последователей бритвы Оккама, не понимаю также как и тех, кто каждый аргумент в отдельный класс оборачивает. Зачем такие крайности?
Кроме того между рефакторингом без тестов и рефакторингом с тестами тоже огромная разница.
Смысл был в том, что есть работа которую намного легче сделать в самом начале, чем потом, но пользу она начнёт приносить потом, а в самом начале выглядит бесполезной.
Например: тесты, хороший скелет, возможно даже с пустыми методами или заглушками, документация, подумать о масштабировании, о декомпозиции.
Когда люди, руководствуясь KISS, бритвами Оккама, вырезают всё, что не нужно прямо сейчас, они усложняют будущее. Не могу сказать, что это плохо. Чем меньше работы в начале, тем более вероятен успех и меньше потери в случае провала. Много думать на перёд рискованно.
Но и совсем не думать не намного лучше. Проект возможно выстрелит, но быстро застрянет и потухнет. Пример выше в тот момент жил чисто на маркетинге.
По-моему, вам при таком подходе совсем не яйца мешали… не помогла бы и крутая ОО модель.
И в итоге, ваше ПО будет разрабатываться быстро (а это деньги) и его будет легче поддерживать чем всемогущего монстра.
Сколько раз вы тратили час на то, чтобы разобраться как аккуратно интегрироваться своим модулем в чужой проект, затем еще час это все отладить, вместо того чтобы за 15 минут написать этот функционал и за столько же его проверить?
Будьте проще, и форки к вам подтянуться.
Мы задаём эту задачу на собеседовании (игру Жизнь), потому что если вы не умеете такого — нам не о чем разговаривать.
Ребята, а сколько из вас реально понимают эти 10 строчек кода с полной реализацией игры Жизнь? Честно говоря, я не понимаю. Я читал это 2 года назад — не понимал. И сейчас не понимаю. Это реализация рисования пикселей на экране, а не игры! Что уж говорить про собеседование — я бы сразу ушёл((
Задача об игре Жизнь не укладывалась в моей голове, а самооценка сильно болела, пока я не убил денёк на свою реализацию — Жизнь/Core. И вот какой парадокс… Мой вариант не доработанный, с безумными абстракциями, на тучу строчек кода для меня выглядит намного естественней! Я знаю, как поменять правила, как замкнуть поле, как играть в трехмерном пространстве… Как запустить по этому полю Динозавра, откладывающего яйца!
Я написал эти классы не для того, чтобы сделать что-то наперёд. Я сделал это так, потому что мыслю такими категориями. И моя голова не может привязать живую клетку к системе координат. Возможно, если бы меня попросили раскрашивать пиксели, я бы смог в 10 строк, а может и не смог бы. Но слово «жизнь» слишком воздействует на моё воображение.
И вот у меня вопрос, а не делятся ли разработчики на два типа:
1) Математики — жонглируют в голове 10 мячами, долго переключаются между абстракциями, пишут про «хватит классы».
2) Философы — быстро переключаются между абстракциями, не могут жонглировать более чем 3-мя мячами, пишут про ООП.
Может есть исследования какие-то в эту сторону? Ну не все могут в голове легко четырёхзначные числа перемножать, и наоборот — кому-то слишком легко говорить метафорами.
Статья в целом по делу, но в тему с “жизнью” автор зря полез. Его реализация работает на моём компьютере более чем в 1500 раз медленнее написанного в лоб с использованием подходящих инструментальных средств алгоритма с массивами (примерно 270 тысяч ячеек в секунду против 433 миллионов). Что должен иллюстрировать такой пример? Что можно быстро написать короткую, малопонятную и очень тормозную программу?
Перестаньте писать классы