![]() |
Для обсуждения: ООП или не ООП? Вот в чём вопрос!
Теология ООП
28-Oct-2004 В последние годы появились весьма неочевидные прогнозы, и даже чуть ли не констатация факта о провале объектной парадигмы, ООП. Крайнюю позицию высказал Ричард Гейбриэл в своем выступлении на OOPSLA под прямым названием "Объектная парадигма провалилась". Другой, более сдержанный и взвешанный прогноз - это Пол Грэм со своей статьей "Языки программирования через сто лет". Объединяет этих двух людей то, что они приверженцы функционального программирования и языка Lisp. "А, да это брюзгливые математики, для которых высочайшим достижением программирования является интерпретатор языка Lisp на языке Lisp в 20 строк" - так бы я отреагировал на эти статьи годами раньше. Но в статье Ричарда Гейбриэла есть слишком много правды, и в ответах оппонентов (например здесь) слишком мало рационального, чтобы можно было не задумываясь пройти мимо этой дискуссии. Оппоненты приводят статистику о том, что все сегодня пишут на ОО языках и используют эти методы прямо во всю. Но это самый глупый аргумент в пользу чего-либо вообще, потому что все каких-нибудь 500 лет назад были уверены, что Земля плоская. Людям всегда нужна какая-то красивая идейная ниша, в которой они будут чувствовать себя комфортно. Находясь в нише ООП, так же как и в любой другой нише-религии, очень трудно заметить что в ней рационально, а что нет. Главное - это комфорт. *** Вместе с миллионами других программистов и я тоже в свое время испытал радость читая первые статьи об объектном программировании, о том, что методы ООП позволяют создавать иерархии классов объектов так, как это можно делать с объектами реального мира. Есть класс плодов, от него производится класс фруктов, от него - класс цитрусовых, затем апельсины, и тут можно уже создавать объекты класса апельсин. Есть что-то общее для всех плодов, для всех фруктов, затем цитрусовых и для всех апельсинов. Спускаясь вниз по иерархии вы добавляете конкретику, когда как вверхах все ужасно абстрактно. А теперь берем абстрактный GUI объект, определяем абстрактный метод paint() - и вперед с песней. Помните? Но именно здесь, на этапе объяснения самой парадигмы нас и ждал подвох. Вернитесь к этим текстам теперь, когда вы уже состоявшийся гуру ООП, и перечитайте их внимательно. Во-первых, тут явно попахивает одной очень старой теорией искуственного интеллекта, согласно которой знания человека можно представить в виде дерева - откуда видимо и вышла собственно парадигма ООП. Как известно, никто с тех пор так и не смог создать "мыслящей" машины на основе такого представления, потому что оно нелепо. Поняв это, создатели некоторых языков и ОО платформ попытались исправить положение (сломать дерево, так сказать) введя множественное наследование. Потом его убрали (Джава), сказав, что это слишком сложно и путает как программиста, так и сам компилятор. А потом снова вернут? Во-вторых. Эти школьные примеры с GUI объектами на самом-то деле и есть область применения ООП. В мире реального программирования многое можно, а иногда даже нужно, делать без этого. Зачастую описывая классы мы даже не задумываемся над тем, а будут ли объекты данного класса persistent настолько, что следует вводить понятие состояния объекта, и тем самым усложнять его реализацию. Какая-то группа данных, т.е. структура, действительно может иметь состояния если того пожелать, но тогда каждая точка входа в эту структуру, т.е. методы объекта, должны прежде сверяться с состоянием и затем только выполнять какие-то действия. Мы просто-напросто усложняем наши программы вводя состояния и сверки там, где в этом не было острой необходимости. Пол Грэм в одной из своих статей писал, что если возможно реализовать что-то в виде обычной функции с самыми обычными параметрами, то следует делать именно так, поскольку функция изолируется и следовательно отлаживается гораздо лучше метода объекта. Далее, один из коньков ООП, который вероятно создает максимальное чувство комфорта у любого программиста, это якобы относительное постоянство интерфейса и наоборот, изменчивость реализации. Описав однажды интерфейс и передав его соседу, вы можете спокойно и не спеша заняться реализацией, совершенно позабыв о бедном соседе. Например, вы можете определить абстрактный интерфейс list и реализовывать его как вам вздумается - хоть связным списком, хоть простым индексным массивом, хоть ассоциатвиным. Были и такие примеры, помните? Сегодня мы уже знаем, что все не так просто. Это правда, что вы можете безболезненно делать коррективы в реализации, в том числе исправлять свои ошибки, но это неправда, что вы всегда можете радикально менять реализацию. Не знаю как вас, но меня практика программирования научила тому, что интерфейс и реализация, при всех наших стараниях уводить их подальше друг от друга, все же слишком тесно связаны. Передать соседу list и не скзать ему как он реализован - значит заставить его когда-нибудь все таки заглянуть в ваш код, потому что этот несчастный сосед обязательно норовит использовать ваш лист самым неэффективным образом и поставить весь проект на грань провала. Он обязательно когда-нибудь заглянет в ваш код и тем самым нарушит одну из заповедей ООП, потому что с черными ящиками жить трудно. А если заглядывать запрещено, например, законами бизнеса, то... В результате в мире плодится огромное количество очень неэффективных приложений на Си++ и особенно Джава, в противовес которым можно найти или написать более компактные и быстрые аналоги на Си. Я не стреляю в Си++, потому что на нем можно писать хорошо, но это могут делать те программисты, которые пришли из мира Си. И наконец, когда апологеты ООП говорят об интерфейсах и о сокрытии реализации, то они вообще-то лукавят потому, что интерфейс в этом смысле есть библиотека, и вовсе необязательно класс. Т.е. ООП фактически присваивает себе то, что ему не принадлежит - понятие переиспользуемого библиотечного кода. *** Еще в 1998-ом году, когда я начал писать свою кустарную альтернативу STL, как вероятно когда-нибудь делали все Си++ программисты, я не смог бы изложить все свои претензии к ООП так пространно, но уже интуитивно осознавал где есть перебор с объектами. Позже моя кустарщина переросла в open-source проект под названием PTypes. Тогда, понимая, что не все должно иметь ОО интерфейсы, я решил экспериментально описать алгебраические интерфейсы там, где нет наследования и полиморфизма. Замечу, что внутри все по-прежнему реализовано в классах, поскольку требовалось, например, перегрузить опреатор + для строк, а вне класса в Си++ такое сделать невозможно. Строка - это атомарный (в смысле фундаментальный) тип, от которого вряд ли имеет смысл производить классы с перегруженными виртуальными методами, так же как и от простого int. Следовательно, интерфейс строки для пользователя может быть алгебраическим: такую простую вещь как length(s) никто не отменял и никто не сказал, что это обязательно должно записываться как s.length(). Точно так же я рассуждал и в отношении списков, и фактически удалось даже привести интерфейсы списков и строк в некотрое соответствие. Например length() был одинаково применим и ко всем типам списков. Делалось это для того, чтобы не загружать пользователя лишними понятиями. Length(), setlength() и некоторые другие методы универсальны насколько это возможно. Позже появился еще и variant, и тоже с алгебраическим интерфейсом. Но были и классы потоков, включая файлы, сокеты и пайпы, описанные в лучших традициях ООП: виртуальные методы, наследование и прочее. Им это очень подходило. Далее я даже умудрился описать шаблоны списков для произвольных базовых типов, сохраняя при этом алгебраические вызовы. Все бы ничего, только со временем я начал получать письма от пользователей с такими жалобами. Они в принципе не против самой идеи, но дело в том, что после усложнения библиотеки компиляторы стали путаться с большим количеством перегруженных функций (не методов!), описанных в шаблонах. Это были на самом-то деле баги в самих компиляторах (причем баги были разные, например у MSVC и GCC). Тут я понял, что такие фокусы с Си++ мало кто вытворяет, и поэтому ошибки в компиляторах остаются незамеченными. Я пытался давать баг-репорты создателям компиляторов, но ими никто не занимался наверное из-за слишком экзотического применения перегрузок обычных функций в купе с шаблонами. Словом, в версии 2.0 библиотеки я вынужденно переписал списки и сделал их чисто-объектными. Ничего страшного, но теперь к сожалению length() уже не применим к спискам, и первоначальная идея библиотеки малость пострадала. К счастью, она по-прежнему популярна, особенно среди новичков, потому что она, кроме всего прочего, позволяет очень быстро запрыгнуть на корабль сетевого и многопоточного программирования и писать очень простой и главное - ясный, читабельный код на Си++. *** Уверен, скоро это станет нормой - равноправное использование объектных и алгебраических вызовов. Должен произойти откат от религии ООП, поскольку программирование, в отличие от наук (а программирование это еще не наука), слишком коммерциализировано, и поэтому чувствительно к неэффективным решениям. Рынок решает все, и он сегодня все чаще жалуется как на ненадежность ПО, так и на слишком большие затраты на его разработку. И рынку наплевать на наши с вами религиозные пристрастия и теоретические баталии. Если вы способны сегодня в одиночку или очень малыми командами создавать сложные системы, в которых ООП будет применятся в сдержанных дозах, то вы начнете очень скоро выигрывать и соответственно хорошо зарабатывать. Или вам нужен не заработок и красивые, компактные решения, а вместо этого - блуждание в дебрях объектной теологии? |
Продолжение
Теология ООП (часть II)
19-Nov-2004 Продолжение статьи "Теология ООП" В этой статье я собираюсь немного попугать вас одной историей о том, как по вине стереотипного объектного мышления в мою программу вкралась весьма неприятная ошибка; далее продемонстрирую пример того, как целый класс можно запросто заменить одной-единственной функцией; и конечно же, как всегда, будет много брюзжания и критики. Но не сердитесь, мы с вами всего лишь пытаемся найти "срединный путь" в проектировании программ и библиотек. *** Подобно тому, как всякий естественный язык оттачивается и пополняется наиболее интеллектуальными его носителями - писателями и поэтами, язык математики формируется на кончике пера абстрактно-мыслящей элиты - математиков. И поскольку процесс формирования алгебраической нотации длится уже не один век, этот язык становится все более естественным в том же смысле, что и обычные языки. Естественность в некотором приближении есть эстетика плюс краткость. Но это так, вообще, о языке математики. Так чем в принципе запись length(s) оличается от s.length() ? Вероятно, принципиальных отличий тут нет за исключением того, что первый способ записи выглядит эстетичнее для тех, кто проходил в школе алгебру и учил ее хорошо. Второй же способ - это некая новая нотация, которая, будучи полностью изолированной (или очищенной - как хотите) от традиционной, приводит к таким странным вещам, как i.add(j). А ведь ОО парадигма поначалу вроде бы пыталась нас убедить в том, что все идет именно к этому: всё есть объекты и методы в них, даже числа и операции над ними. Но постойте, нотация i.add(j) не является ни эстетичной, ни краткой в сравнении с i+j. Конечно, программирование - это уже не математика (или еще не математика?), и оно имеет право вводить собственные абстракции. (Сами математики, к слову сказать, внеся некоторые дополнения и коррективы в уже имевшийся у них язык, получили Lisp, и весьма счастливы.) Вопрос лишь в том, чтобы вновь вводимые абстракции и нотации были достаточно кратки, выразительны, красивы, и что самое главное - заставляли бы думать человека таким же образом. Всегда можно распознать в толпе математика по лаконичности и меткости его речи, поскольку внутренний язык у хороших математиков - это по сути математика. Что же дает программисту ООП и какое мышление оно у него формирует? Затрудняюсь сказать, но скорее всего ничего интересного ООП у программиста не формирует. Может быть потому, что эта абстракция еще слишком молода и далека от состояния отточенности и естественности. Впрочем, перейдем от предположений к конерктным примерам. *** Существует множество объектных библиотек-оберток для базовых системных сервисов, в том числе и для интерфейсов многопоточного программирования. Обычно сами системные API навязывают нам объектный подход: они как правило создают дескриптор (handle), через который и предполагается манипуляция неким системным объектом, например файлом, графическим элементом или потоком исполнения. Все что остается сделать разработчику "обертки" - это просто инкапсулировать дескриптор внутри класса и затем переписать вызовы системного API в методы. Другими словами, буквально перевести все на язык ООП. И я тоже рассуждал приблизительно так же, когда описывал классы для многопоточного программирования в PTypes. Класс thread не был исключением, кроме разве что одной тонкости, связанной с запуском потока: дело в том, что системный вызов pthread_create() (или BeginThread() в Windows) не может быть в конструкторе класса, как это часто делается для дескрипторных интерфейсов. Вместо этого, создание дескпритора и запуск асинхронной функции был перемещен в отдельный метод thread::start(). Но дело, собственно, не в этом. Объекты этого класса имеют опцию autofree, которая указывает должен ли объект самоуничтожиться по окончании выполнения асинхронной функции thread::execute(). Так вот, на старых Linux-системах, базирующихся на LinuxThreads, PTypes мог вылетать со странными ошибками порчи памяти (memory corruption). Отладка показала, что LinuxThreads почему-то иногда записывает дескриптор потока в области памяти, в которых когда-то существовал мой объект типа thread, но его в этом месте уже нет. В чем же дело? Посмотрите на описание pthread_create(). Вы передаете этой функции ссылку на место в памяти, куда система должна записать новый дескриптор потока. По поводу запуска вашей асинхронной функции start_routine не дается никаких гарантий, но вы надеетесь, что она когда-нибудь будет вызвана. Моя ошибка состояла в том, что асинхронная функция могла быть вызвана и закончена еще до того, как LinuxThreads успевал записать дескриптор в соответствующее поле моего класса. И в случае autofree потока это приводило к порче памяти, поскольку выходило так, что объект удалялся из памяти еще до того, как основной поток вернется из pthread_create(). Интересно, что кроме старых версий Linux ни одна другая система не делала этого в таком порядке, вероятно предвидя потенциальные ошибки вроде моей. Но если сделать, как говорят киношники, отъезд и взять общий план, то моя ошибка на самом деле происходит от предположения о том, что pthread_create() является конструктором системного объекта. А он таки им не является, или скорее не вписывается в традиционное понятие конструктора, несмотря на внешнюю схожесть. Виной всему - мое стереотипное объектное мышление. Впрочем, какая-то доля вины тут должна пасть и на разработчиков стандарта POSIX Threads. Размышляя потом над всем этим я также понял, что на самом деле не только pthread_create() не является конструктором, но еще хуже: поток исполнения вообще не является объектом, и следовательно архитекторам POSIX нечего было водить нас за нос своими дескрипторами. Другие функции, использующие дескриптор потока - pthread_join() и pthread_detach() - избыточны и могли быть изъяты из интерфейса (синхронизацию с завершением потока можно реализовать в приложении при помощи семафоров). Если бы создатели PThreads были бы истинными минималистами, то они оставили бы только pthread_create() и уже без того параметра, принимающего дескриптор. В ядре Linux поддержка потоков долгое время ограничивалась одной-единственной функцией clone(), пока наконец начиная с версии 2.6 публике удалось убедить Линуса Торвальдса ввести полную поддержку POSIX-интерфейса в ядро. Я не в курсе какие при этом приводились доводы, но скорее всего не приводилось ничего путного кроме "POSIX это стандарт". Но стандартный интерфейс может быть таким же несовершенным, как и любой нестандартный, и наоборот. Впрочем, это отдельный разговор. Конечно же, на уровне приложения иногда полезно описывать классы-обертки для потоков исполнения, но суть вопроса не в этом. Надеюсь уже понятно в чем именно: следует быть осторожнее с ОО-мышлением. И подозреваю, что такая нетривиальная вещь, как потоки исполнения, на самом-то деле оказалась не по зубам объектной парадигме. *** Другой пример, на сей раз без ужасных ошибок с разрушением памяти: сокеты, и в частности дейтаграммные сокеты. Уже заранее могу вам сказать, что дейтаграммные сокеты не являются объектами, и они по сути притянуты к системному интерфейсу сокетов "за уши" ради единообразия, но из-за этого только вносят путаницу. В той же самой библиотеке PTypes по пожеланиям пользователей пришлось ввести интерфейс для дейтаграммных сокетов. Недолго раздумывая, я описал два класса ipmessage и ipmsgserver по образу и подобию их поточных эквивалентов ipstream и ipstmserver. (Возможно, для вас непривычен стиль именования в PTypes, но использование этого стиля обосновано: его можно комбинировать с любым другим в одной программе. Если бы PTypes был написан, например, в венгерской нотации, то как минимум один класс программистов - юниксоиды старой школы - были бы жутко недовольны.) В конце концов это всего лишь обертка для системного интерфейса сокетов, и я ничего не пытался менять в этой идеологии. Сам я никогда не использовал протокол UDP в своих программах, и поэтому развитие этой части библиотеки всегда опиралась на отзывы пользователей. И из этих же самых отзывов я понял, что такой интерфейс для дейтаграмм может легко путать программиста. Работа с дейтаграммными протоколами сводится к трем основным операциям: посылка пакета, привязка к порту и "слушание" его, получение пакета. Если взять только операцию посылки, то окажется, что для ее осуществления достаточно одной-единственной функции. По сути посылка, если можно так сказать, не имеет состояния, и поэтому нет необходимости описывать класс и размножать объекты; в нашем случае - это класс ipmessage, который таким образом оказывается избыточным. Что касается привязки и получения, то здесь ситуация иная: такой сокет имеет состояние, поскольку система параллельно с вашим приложением должна слушать определенный порт и буферизировать поступающие пакеты. Поэтому, такой класс как ipmsgserver на самом деле нужен, правда даже в нем в принципе есть кое-что лишнее: это методы посылки. Скорее всего в следующих релизах библиотеки я заменю класс ipmessage на обычную глобальную функцию для посылки дейтаграмм. Класс же ipmessage можно оставить для совместимости и еще для тех, кто со всем этим не разобрался. *** |
Многие программисты рассматривают ООП, кроме всего прочего, как средство описания небольших модулей в рамках приложения. Любой язык программирования, имеющий даже самое неполное ОО-расширение, позволяет хорошо изолировать миниатюрные интерфейсы в общем пространстве имен программы. Такой подход помогает нам мысленно изолировать небольшую функциональную единицу и заняться ее проектированием в отрыве от всего приложения.
И тут мы временами можем сталкиваться с трудностями, связанными с семантической принадлежностью того или иного метода данному классу. Например, принадлежность метода paint() некой абстрактной визуальной компоненте почти не вызывает сомнения. Но как быть с методом, который вставляет данную компоненту в список дочерних элементов родительской компоненты? Должен ли это быть метод add_child() в родительском интерфейсе, или set_parent() в дочернем (или может и то, и другое)? Я бы предпочел первый вариант, но в GUI-интерфейсах чаще встречается как раз таки второй, потому что дочерний объект должен еще и удалить самого себя из списка предыдущего "родителя". А что если попытаться разрешить проблему выставив этот метод за пределы класса? Представьте себе, вы имеете глобальную функцию set_affinity(parent, child), которая, возможно, вызывает защищенные виртуальные методы оповещения как в родительском классе, так и в дочернем. Не вижу в этом ничего страшного, и даже более того, мне будет легче запомнить тот факт, что set_affinity() никому не принадлежит, чем пытаться вспомнить в каком интерфейсе его следует искать: в родительском или дочернем. И все потому, что set_affinity() по сути никому не принадлежит и является "нейтральным" действием, в котором принимают участие больше одного объекта. Другой пример: обычно базовые классы, реализующие подсчет ссылок, объявляют по крайней мере два метода: acquire() и release() внутри этого абстракного интерфейса, которые увеличивают или, соответственно, уменьшают счетчик ссылок. Но возникает вопрос: насколько метод release() принадлежит данному объекту? Ведь в результате вызова этого метода объект может быть уничтожен, следовательно он является чем-то нейтральным скорее чем является "собственностью" объекта. В PTypes оба этих метода объявлены глобальными (правда в случае acquire() - только ради симметрии с release()). Примеров можно найти немало. Возьмите хотя бы преобразование строки в число и обратно: если в вашем языке строки и численные типы являются объектами, то каким именно классам должны принадлежать функции преобразования? На самом деле они по своей природе никому не принадлежат и являются самыми обычными глобальными функциями, а объявление их, к примеру, в классе string не дает никакого преимущества. Вы не выигрываете от этого ровным счетом ничего, или может даже проигрываете в естественности и интуитивности интерфейса. Кстати говоря, вовсе необязательно, чтобы такие нейтральные функции были объявлены буквально глобальными: вы вполне можете найти для них место в каком-то другом классе, лишь бы это выглядело логично. Например, тот же set_affinity() может оказаться в объекте окна (ведь визуальные компоненты так или иначе "живут" в окне), а пара acquire()/release() - в каком-нибудь class factory, которые нынче очень модны. Все это вам может и не понравиться, но лучше подумайте о том, что естественность интерфейса важнее привычек. А привычки ОО методологии настолько липучи, что, как видите, мы временами можем закрывать глаза на противоестественность в нашем коде. *** У меня в данный момент нет из всего этого готовых конкретных выводов в стиле "следует писать программы так-то, и не следует писать так-то", поскольку любой такой вывод был бы уязвим для критики. Но есть одна вещь, с которой вы не можете не согласиться: интерфейсы стоят того, чтобы им уделялось много времени на обдумывание. Реализация - это сосвем другая стихия, которая является сутью нашего с вами ремесла, но интерфейсы библиотек - это языки, на которых мы предлагаем думать и писать другим программистам. Я никогда не жалею своего времени, чтобы оптимизировать интерфейс, сделать его более компактным и естественным, если даже ради этого придется пойти наперекор собственным объектно-ориентированным привычкам. Попробую сделать еще один, уже более общий и менее очевидный вывод: следует проявлять консерватизм и минимализм в таких базовых вещах, как языки программирования, generic библиотеки и ядра операционных систем. В то же время, эти свойства становятся менее уместными по мере того, как вы поднимаетесь вверх в направлении к конечному пользователю. |
Ну, и как положено, ссылка на оригинал:
http://www.melikyan.com/dalshe/articles/oop2.html http://www.melikyan.com/dalshe/articles/oop.html Предлагаю высказать свои мнения... Особенно было бы интересно услышать мнение программистов, относящихся с идеологии *nix. |
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
На полугодичных курсах по программированию максимум чему могут научить - синтаксису какого-то конкретного языка программирования, может быть основам ООП, но никак не научить программировать, или точнее, конструировать ПО. |
Цитата:
|
Цитата:
P.S. На мой взгляд весьма грамотная статья. Повальное увлечение ООП (опять же по моему личному мнению) приводит к избыточности кода, попыткам представить объектами всего чего бы то ни было, даже если это самое ну ни как не хочет представлятся объектом )). Практически везьде нужна золотая середина, в том числе и в данном вопросе. |
Цитата:
|
Цитата:
|
Цитата:
ЗЫ вопрос не снят. |
Цитата:
Вопрос: А Вы сами то к программированию каким боком? Больно вопросы у Вас... |
Цитата:
|
Цитата:
|
Цитата:
ИСпользуя принципы ООП, а точнее, используя огромное количество библиотек классов, написанных для того или иного языка, неопытный пользователь может взять какой-нибудь учебник и написать все примеры, которые там есть, но врядли сможет написать что-то более практичное, особенное если сложность проекта будет больше 1000 строк кода (кроме автогенерируемых). Хороший программист это в первую очередь - жесткие правила для себя, жесткая система, а этому врядли учат в каком-нибудь ПТУ. И ещё, моё лично мнение, чтобы начать изучать ООП, надо сначала изучить структурный подход. Только владея несколькими методиками, можно эффективно писать программы, применяя в той или иной ситуации разные инструменты. Вот простой пример. Перед программистами стояла задача написать программу (определенные аппаратные средства), которая бы собирала данные с термодатчиков (термосопротивления), и для фильтрации значений вычисляла многочлены 16-20 степени (для каждого отсчёта и каждого датчика). Так вот, никакие ухищрения, в том числе и напиание кода на ассемблере, не позволяло достичь приемлемого уровня производительности. Простым решением было заставить сами датчики обрабатывать данные и сообщать супервизору уже готовые отфильтрованные значения. При этом стоимость самих датчиков выросла не сильно, а их точность и удобство использования только увеличились. Иногда, чтобы эффективно решить задачу, нужно выйти даже не за рамки языка, а за рамки компьютера... выйти в 4е измерение. В) |
Цитата:
Кстати, кто тут спрашивал про "грамотное приложение"? Неграмотно написаное, но рабочее приложение не является программным продуктом?:) Цитата:
|
Цитата:
2) По поводу функционального: Извените, но с моей точке зрения, вы опять не очень верно написали. Вы пишите. что с помощью функционального программирования не возможно использование сокрытия реализации.. но берем ту же Windows API или любую другую API, тысячи функций, о которых (очень часто) программист знает только название, параметры и выполняемое действие. То же самое сокрытие реализации не так ли? Другой вопрос. что реализовано не так надежно и удобно. 3) теперь по поводу "грамотного приложения". Программирование чрезвычайно коммерцианализированная наука (хотя программирование, вроде, еще не является наукой). И неграммотно написанное приложение проиграет конкуренцию. В книжке Станислава Жаркова Shareware: профессиональная разработка и продвижение программ описан очень хороший пример. Рассматривается два практически идентичных приложения, представляющих сервис Who is? только одно написано на Си и весит пару кило, другое на VB и весит почите полтора метра, какое по вашему приложение скачают большее количество пользователей? Даже если не зацикливаться на коммерции, то какую программу предпочтут конечные пользователи - маленькую, быстро и надежно работающию или же громадную, полную багов, отчайно тормазящию даже на мощных компьютерах? В свете вышеизложенного, по моему мнению, неграмотно написанное приложение. вполне можно не считать приложением. (Про неуловимого Джо, думаю, все анекдот помнят) Цитата:
|
Я понял в чем тут фишка: Вы как и остальные оппоненты не считаете программирование профессией, а программистов - рабочими. Для Вас программирование это призвание и талант которые либо есть либо нет. Есть "настоящий" программист, которого Вы собственно и подразумеваете под этим словом, и есть "индивидуум который скачает все неообходимые для написания тетриса классы, реализация законченного приложения потребует очень малого времени, минимальнейших знаний как в ООП, так и вообще в программировании". Вы забываете, что в современной индустрии программирования последних абсолютное большинство. И все крупные програмные проекты вобщем-то создаются именно этими индивидуумами, которые каждый сам по себе лепят модули на основе имеющихся классов по заданию руководства, чаще всего даже не зная для чего они предназначены. В этих проектах с такой точки зрения программистом можно считать только архитектора проекта.
Теперь непосредственно по сути: Цитата:
Цитата:
Цитата:
ЗЫ а насчет сравнения пользователей и программистов: не так далеко еще ушли те времена, когда быть пользователем было не намного легче чем программистом, а в некоторых случаях и сложнее. Почему Вы не думаете, что это может повториться с программированием? :) |
Цитата:
Цитата:
Цитата:
|
Не буду спорить ибо различный смысл вкладываемый в понятия остается: существуют миллионы программистов не качающих гигами книги, не изучающих ничего нового выходящего за рамки работы и тд по всем пунктам. Это в любой профессии, есть кому работа интересна и он в ней совершенствуется, а есть кому неинтересна и они работают от звонка до звонка. Вы приводите в пример почему-то только первых. А меж тем я как раз имел ввиду, что ООП облегчает жизнь вторым и следственно их будет больше.
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
|
Ну вот и выяснили, что никаких мыслей я Вам не приписываю ведь фраза "Почему Вы не думаете..." больше похожа на вопрос :)
Интересно кому нужны плохие учителя, слесари, строители? Кто их на работу берет? А ведь все они где-то работают, и программистам место найдется :) И весь мой первый пост сводился в общем-то к тому, что ООП победит, потому как это очередной шаг к тому, чтобы сделать программирование общедоступным. Есть конечно узкоспециализированные области где он непройдет: в осн некоторые направления оборонки и научных рассчетов, но массовое будующее именно за ним, пока не появится что-то что еще более упростит процесс программирования несмотря на усложнение собственной внутренней структуры. Любая профессия начинает развиваться только тогда, когда на смену избранным гуру приходит зарабатывать деньги массовый средненький работник не хватающий звезд с небес. Именно к этому и делает шаг ООП. |
| Текущее время: 08:34. Часовой пояс GMT +3. |
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot