Почему не абстрактное программное обеспечение в более масштабном масштабе?

Рассмотрим следующий пример:

Пользователь хочет, чтобы программа вычислила несколько чисел фибоначчи. Звучит достаточно просто. псевдокод:

stdout.write("How many fibonacci numbers do you want to calculate? ")
int count = int(stdin.readline())
while count>0:
    stdout.writeline(calculate_next_fibonacci_number())
    count--

Даже очень простая программа, подобная этой, уже испорчена:

  • Программа записывает на stdout. На самом деле это не то, что планировал программист, не так ли? Цель состоит в том, чтобы отобразить кучу номера для пользователя, не , чтобы написать какой-то текст в stdout - нет гарантии, что пользователь когда-либо увидит текст, написанный на стандартный вывод.
  • Аналогично, пользовательский ввод считывается из stdin, который представляет собой текстовый (или файл, если вы предпочитаете) интерфейс, когда на самом деле программе требуется число, а не текст. Это кажется принципиально неправильным.

Давайте подумаем о том, что мы пытаемся сделать более абстрактно. Мы хотим:

  • Вычислить кучу чисел. Сколько стоит пользователь.
  • отображает результаты для пользователя.

Почему же мы не пишем код именно так? (Большинство) языков программирования предоставляют эту вещь, называемую «функцией», которая принимает параметры и использует их для чего-то. Это не похоже на то, что мы пытаемся сделать?

void display_fibonacci_numbers(
        int number "how many fibonacci numbers to calculate"):

        Sequence<int> numbers
        while number>0:
            numbers.append(calculate_next_fibonacci_number())
            number--

        notify(numbers)

display_fibonacci_numbers()

Этот код, конечно, не завершен - функция notify не реализована нигде, и пользователю нужен какой-то способ ввода число. Я мог бы представить себе операционную систему пользователя или диспетчер рабочего стола или что-то еще, чтобы позаботиться об этом - он мог отображать терминал, он мог бы генерировать графический интерфейс, он мог бы сказать, что пользователь записывает номер в воздух своим носом; в любом случае это не так ( должен ), я программист.


Я считаю, что программное обеспечение должно быть более абстрактным.

Несколько примеров.

  • взаимодействие между процессами. Как ты делаешь это? Розетки? Сигналы? DBus? Файлы? Цель состоит не в использовании сокетов, сигналов или dbus, а в том, чтобы общаться с другим процессом. Почему не что-то вроде Process.from_name("Music player").play_random_song()?
  • Загрузка файлов. local_file.write(remote_file.read())? Почему бы не download(url), который мог, в зависимости от конфигурации системы, сразу начать загрузку, но с низким приоритетом, чтобы не замедлять вниз других загрузок или добавить его в очередь загрузки, которую нужно загрузить позже, или что-то еще?
  • Пути файлов. Почему, на самом деле, пути к файлам все еще строятся (по крайней мере, на большинстве языков)? Почему нам приходится иметь дело с тем, является ли разделитель путей / или \, будь то ., .. или что-то еще? Почему нет класса FilePath, который позаботится об этом?

Идя дальше, почему бы не применять концепцию утиной печати к модулю? Например, в python HTML часто анализируется с помощью модуля beautifulsoup:

from bs4 import BeautifulSoup

page= BeautifulSoup(urlopen('http://test.at'))

Опять же, цель программиста заключалась не в использовании BeautifulSoup, а в анализе HTML. Почему бы ему прямо сказать, что его код использует модуль BeautifulSoup? Он действительно хочет

import HTMLParser
page= HTMLParser.parse(urlopen('http://test.at'))

Утиная печать для модулей: кому нужен какой модуль, пока он делает то, что я хочу?


Почему программирование не так? Я что-то замечаю, что делает все это невозможным (или непрактичным)?

6 голосов | спросил Aran-Fey 9 TueEurope/Moscow2014-12-09T16:35:06+03:00Europe/Moscow12bEurope/MoscowTue, 09 Dec 2014 16:35:06 +0300 2014, 16:35:06

9 ответов


20
  

Почему программирование не так?

Почему вы так думаете? На самом деле, программирование есть . Конечно, вы не можете это сделать в ассемблере. Поэтому мы придумали языки, которые могут быть более похожи на человеческие мысли.

Хорошие программы программистов похожи на примеры, которые вы дали. Но это не так просто. Сначала вы должны понять, каково это требование. Это уже достаточно сложно, и большинство людей не могут правильно разработать, что им нужно, поэтому хороший разработчик программного обеспечения должен действительно понять, чего хотят люди, а не то, что они говорят.

После этого вы должны увидеть концепции, стоящие за реальным миром. Это довольно философски и требует большого опыта. И затем, после этого, вы должны перевести эти результаты на язык по вашему выбору, работая над неспособностями, которые каждый язык имеет и выбирает правильный уровень абстракции (вы не хотите, чтобы что-то слишком сильно переоценили?).

Не все люди хороши в этих шагах или даже осведомлены из них. Даже в небольших примерах видно, что это не тривиально. Возьмем вашу функцию display_fibonacci_numbers и посмотрим, что мы можем улучшить там (даже если это не codereview.stackexchange здесь).

void display_fibonacci_numbers(

Именование действительно не очень точное, потому что вы очень точно указали в виде номеров, которые вы правильно покажете? Это должно описываться именем функции.

    int number "how many fibonacci numbers to calculate"):

Почему это int? Это верно для конкретного и даже неправильного, потому что ints может, конечно, иметь отрицательные ценности? Так что вы действительно можете захотеть, это тип, который можно использовать для вычисления чисел фибоначчи. Возможно, natural number?

    Sequence<int> numbers
    while number>0:
        numbers.append(calculate_next_fibonacci_number())
        number--

Означает ли это, что вы намереваетесь делать? На естественном языке (который часто является хорошим приближением) мы бы сказали: «Создайте список указанного количества чисел фибоначчи». Я ничего не могу прочитать об уменьшении числа здесь, я ничего не могу прочитать о статическом значении 0. Также ничего о функции "calculate_ next _fibonacci_number ()".

Следовательно, в Scala я бы, например, напишите код как List.fill(number)(randomFibonacci())

Он не читается точно так же, как на естественном языке, но он по крайней мере содержит ту же информацию.

Я хотел привести вам эти примеры, чтобы показать вам, что это сложно написать таким образом. Вам нужно иметь опыт, потратить много времени на размышления о вещах, уметь находить правильные концепции и абстракции, а THEN иметь язык, который не мешает вам выразить их в сжатой форме. Вот почему не многие так программируют. И еще хуже: люди привыкают к вещам. Поэтому, если вы всегда программируете на языке, который мешает ему сделать последний шаг, он, возможно, продолжит программирование на новом языке, как в старом.

ответил valenterry 9 TueEurope/Moscow2014-12-09T17:01:03+03:00Europe/Moscow12bEurope/MoscowTue, 09 Dec 2014 17:01:03 +0300 2014, 17:01:03
13
  

Почему же мы не пишем код точно так же?

Мы делаем. Ваш пример Фибоначчи является явным нарушением принципа единой ответственности. Один из методов должен отвечать за генератор, который обеспечивает последовательность Фибоначчи. Другие части затем отвечают за принятие N значений из него или пропускание значений N или получение ввода и т. д.

  

Я бы предположил, что пользовательская операционная система или менеджер рабочего стола или что-то еще позаботится об этом - он может отображать терминал, он может генерировать графический интерфейс, он может сказать, что пользователь записывает номер в воздух своим носом; в любом случае это не (не должно) беспокоить меня, программист.

Иногда это не касается программиста. В этих случаях вы используете некоторую абстракцию пользовательского интерфейса, которая делает этот клей, чтобы превратить «получить номер» и «распечатать эти числа» в реалистичные реализации платформы. Они уже существуют и обычно используются.

Но вам не хватает точки.

Подавляющее большинство работы программиста - это не все эти программы, а склеивание разрозненных битов существующего кода. Уже существует код для создания последовательности Фибоначчи. Уже есть код для первого N последовательности. На этой платформе уже есть код для печати номеров.

Единственная причина, по которой вы находитесь, состоит в том, что кто-то хочет собрать все те бит кода. Почему же это не первые N простых чисел? Специфика того, как получать входные и выходные данные, является столь же жизненно важным, как и какая последовательность для использования.

  

Почему не что-то вроде Process.from_name («Музыкальный проигрыватель»). play_random_song ()

AppleScript уже делает такие вещи. WCF во многом уже абстрагирует механику общения из семантики коммуникации.

  

Почему бы не скачать (url)

C # (и другие) уже имеют библиотеки для этого. Конечно, у них уже есть хорошо определенная семантика, потому что конфигурация является подлым. Это код без какой-либо рамки /процесса для создания кода с качеством. Хуже того, он удаляет из вашего реального кода любое качество (а часто и производительность).

  

Почему нет класса FilePath, который позаботится об этом?

C # (и другие) уже имеют библиотеки для этого.

  

Идя дальше, почему бы не применить концепцию утиной печати к модулям?

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

Проблема заключается в том, что подавляющее большинство «как это работает» определяется интерфейсом к модулю. Одна реализация будет иметь автоматическое закрытие потоков файлов, а другая будет использовать Open и Close. Это строго разные интерфейсы.

  

Почему программирование не так?

Есть лодка причин.

Вероятно, наиболее убедительным является этот тип сценария . Независимо от того, что ваш контроль ОС, как вводить /выводить, делает программистов более быстрым, быстрее, какой-то деловой человек хочет, чтобы вы делали что-то другое, чтобы «различать».

ответил Telastyn 10 WedEurope/Moscow2014-12-10T18:06:49+03:00Europe/Moscow12bEurope/MoscowWed, 10 Dec 2014 18:06:49 +0300 2014, 18:06:49
11

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

Проще говоря: потому что, когда вы переходите к нему, абстракции не делают do . Реализации. И чем более абстрактна ваша программа, тем больше разводится она от того, что происходит на самом деле - тем сложнее понять, что делает код.

Во-первых, наивному разработчику, конечно, кажется, что сосредоточиться на достижении высокого уровня цели того, что должен делать код и «абстрагировать детали реализации», делает код более понятным, но я с уважением представляю что любой, кто считает, что у него мало опыта в отладке. Если в коде что-то не так, особенно если это уже выпущенный код, и у вас есть клиенты, которые недовольны этим и хотят исправить now , тем быстрее вы сможете найти, где проблема есть, тем лучше. И необходимость выкапывать слои по слоям на слоях абстракций делает это сложнее, а не проще.

Поскольку современный жизненный цикл разработки программного обеспечения тратит гораздо больше времени на техническое обслуживание, чем в оригинальной разработке, все, что способствует быстрой первоначальной разработке и высокой абстракции за счет обслуживания, удобочитаемости и отладки, следует рассматривать как мета-пример преждевременной оптимизации.

Не поймите меня неправильно. Я не против абстракции, где это имеет смысл. Но слишком часто вы видите, что люди добавляют все больше абстракции только ради абстракции, и это превращает код в беспорядок сложности, а не уменьшает сложность. Помните совет, который знаменито приписывается Эйнштейну: все должно быть как можно проще, но не проще.

ответил Mason Wheeler 9 TueEurope/Moscow2014-12-09T16:57:04+03:00Europe/Moscow12bEurope/MoscowTue, 09 Dec 2014 16:57:04 +0300 2014, 16:57:04
6

Вы обнаружили хороший факторинг. Поздравляю.

Почему больше людей не программируют так? Потому что трудно увидеть преимущество в том, чтобы делать что-то таким образом, что кажется больше усилий и будет окупиться позже, когда меняются требования. Люди недальновидны; даже те, кто может мыслить достаточно абстрактно, чтобы стать программистами, недальновидны. Некоторые из них немного менее близоруки, и, как правило, они изобретают редкий трюк или образец, который в конечном итоге удается установить и поднять общее качество программного обеспечения немного.

Затем кто-то изобретает блестящий новый канал распространения со странным ad-hoc kludgy языком программирования, чтобы пойти с ним, и все успехи идут быстро из окна. Не чувствуйте себя плохо, это так, как мир:)

ответил Kilian Foth 9 TueEurope/Moscow2014-12-09T16:39:02+03:00Europe/Moscow12bEurope/MoscowTue, 09 Dec 2014 16:39:02 +0300 2014, 16:39:02
6

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

  

«Все проблемы в информатике могут быть решены другим уровнем косвенности, за исключением, конечно, проблемы слишком большого числа направлений». -Давид Уилер

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

Если бы мы решили создать абстрактный синтаксический интерфейс HTML, потратьте время на его разработку, а затем внедряете экземпляр интерфейса, который использовал BeautifulSoup, мы потратили впустую наше время? Наверное, если мы только используем наш фантастический интерфейс для вызова BeautifulSoup. (Обратите внимание, что предлагаемая замена BeautifulSoup в вашем вопросе по существу ничего не сделала для вас, кроме как изменить имя от BeautifulSoup на HTMLParser.)

Обертывание чего-то, что не обязательно должно быть обернуто в первую очередь, является пустой тратой времени.

С другой стороны, если мы собираемся написать программу, которая использует BeautifulSoup для большинства синтаксических разборов, но иногда действительно нужны возможности синтаксического анализа UglyOatmeal или SloppySandwich, интерфейс, который их обертывает, может сэкономить нам много времени и усилий ,

Кажется, вы думаете, что детали не должны касаться вас как программиста. Это только иногда верно; некоторые детали уже обрабатываются оборудованием, ОС, языком программирования и библиотеками. Другие детали важны в корне таким образом, что их невозможно обрабатывать автоматически - например, в вашем примере с фибоначчи, для поведения программы важно, является ли тип номера int или типом, который может обрабатывать большие числа. Иногда детали представления чего-то имеют большое значение для производительности.

Приятно, когда все обрабатывается автоматически для нас, но обычно бывает какая-то стоимость. Часто стоимость - это производительность, и часто это недостаток контроля над чем-то.

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

Мы не нуждаемся в абстракции more , нам нужны правильные абстракции в нужных местах. Абстракция - один из наших самых мощных инструментов программирования, но есть способы злоупотреблять им или нереалистично ожидать, что он будет делать магию.

ответил Michael Shaw 11 ThuEurope/Moscow2014-12-11T01:58:01+03:00Europe/Moscow12bEurope/MoscowThu, 11 Dec 2014 01:58:01 +0300 2014, 01:58:01
2

Закон уменьшающихся возвратов применяется к абстракции точно так же, как и все остальное. Лучше ли конфигурировать устройство с помощью перемычек или DIP-переключателей? Возможно, DIP-переключатели, которые являются абстракцией по соединительным проводам перемычки. Лучше ли программировать на языке машины или на ассемблере? Ответ - почти наверняка ассемблер. Мне сложно подумать о каком-то сценарии, в котором вы бы не хотели, по крайней мере, использовать ассемблер для генерации вашего машинного языка.

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

Пример: я работаю с несколькими системами PAAS, которые пытаются сделать сложную задачу интеграции с другими системами более абстрактной и простой. Я постоянно задумываюсь над тем, что действительно происходит под чистым фасадом, представленным такими системами:

  • Что означает слово «пустое значение» в этой метке флажка? Означает ли это, что исходная строка присутствует, но значение столбца равно null? Означает ли это, что исходная строка отсутствует? Означает ли это то, что? У этого конкретного инструмента PAAS даже есть понятие true /false /null? Если да, то какие поля имеют значение NULL (и этот параметр где-то заглублен в диалоговом окне, чтобы сделать пользователя более абстрактным)?

  • Когда я выберу параметр «Добавить записи в целевую базу данных», будет ли это обновление также записано? Я не вижу вариант «обновления» ... поэтому «добавить записи» тоже нужно делать обновления ... правильно? (Это может показаться нелепым примером, но это реальный вариант. И да, я в конечном итоге оказался в Google, пытаясь определить, действительно ли «добавить» означает «добавить /обновить» для одного конкретного параметра в одном конкретном инструменте PAAS - это ваша идея хорошего опыта разработчика?)

Трудно ответить на эти вопросы, так как все эти материалы программиста были тщательно скрыты, заблокированы в реализации черного ящика и т. д. во имя представления абстрактного пользовательского интерфейса. В итоге мне сложно даже сформулировать необходимые вопросы (будь то в Google или при технической поддержке). Мне интересно о таких вещах, как операции с недействительностью и «вверх», но мои собеседники активно избегают использования таких низкоуровневых технических терминов. Но эти вопросы нуждаются в для ответа на интеграцию ...

И мой последний момент намекает на возможность того, что, развивая более общий язык вычислений, мы сможем работать на более абстрактном уровне. Если не программисты (в том числе дизайнеры GUI) будут использовать стандартные термины, такие как nullable, «upsert», внешний ключ и т. Д., Тогда, возможно, многие вещи, которые в настоящее время выполняются с использованием кода, могут выполняться графически или иным образом более абстрактным образом. Но когда люди говорят «добавить» вместо «upsert», потому что «upsert» - это страшный язык программиста, ну, я должен откинуться на свои старые, низкоуровневые навыки и инструменты, чтобы действительно выполнить работу.

ответил user1172763 10 WedEurope/Moscow2014-12-10T17:57:39+03:00Europe/Moscow12bEurope/MoscowWed, 10 Dec 2014 17:57:39 +0300 2014, 17:57:39
2

Что вы спрашиваете: «Почему мы не можем использовать Z или UML , чтобы полностью прототипировать и спроектировать систему?"

И ответ на , что : «Потому что, когда вы могли строить что-то, что создавало бы систему на основе спецификации UML или Z, проверка spec становится столь же сложным (если не более), чем реализация спецификации.

ответил warren 16 TueEurope/Moscow2014-12-16T22:42:55+03:00Europe/Moscow12bEurope/MoscowTue, 16 Dec 2014 22:42:55 +0300 2014, 22:42:55
1

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

Я собираюсь использовать вашу строку пути файла в качестве примера:

  

Пути файлов. Почему на земле все еще есть пути к файлам (в большинстве   языки, по крайней мере)? Почему нам приходится иметь дело с тем,   разделитель есть /или \, будь то., .. или что-то еще? Почему нет   Класс FilePath, который позаботится об этом?

Иногда эти абстракции существуют, но не на самом языке программирования. Эта возможность поддерживает Microsoft Windows, .NET Framework и семейство языков программирования, которые используют .NET и работают в Windows. http://msdn.microsoft .com /EN-US /библиотека /system.io.path% 28В = vs.110% 29.aspx

На самом деле это не часть языков программирования (VB.NET, C #, F # и т. д.), а структура. Я вижу эту платформу .NET как абстракцию всей сантехники, которая необходима и не является частью логики или алгоритмов, которые нам необходимо создать в нашем коде. Программист может использовать этот объект из платформы .NET или создать свой собственный. Ваш аргумент кажется, что создать свою собственную - плохая идея, потому что есть что-то лучшее, что доступно больше, так почему же дать разработчику выбор? Я не уверен, как вы отбираете этот выбор. Не допускать, чтобы строка местоположения файла могла взаимодействовать с файловой системой каким-либо образом в форме или форме? Вы можете программировать только для Windows, если вы используете соответствующую структуру и семейство языков? Как вы получаете URL-адрес из Интернета? Должен ли он прибывать в виде объекта .NET IO?

ответил JeffO 10 WedEurope/Moscow2014-12-10T17:41:42+03:00Europe/Moscow12bEurope/MoscowWed, 10 Dec 2014 17:41:42 +0300 2014, 17:41:42
0

Многие из ваших примеров, похоже, являются проблемами в поиске решения. В реальном сценарии ваша функция числа Фибоначчи будет фактически функцией, которая принимает 1 или 2 (для произвольных подмножеств последовательности Фибоначчи) int и возвращает список целых чисел, а вызывающий процесс будет обрабатывать ввод и отображение выход. Если у вас есть код, который вы предоставили в реальном мире, это связано с тем, что разработчик никогда не предполагал, что он будет чем-то другим, кроме того, что он побежал из командной строки.

Для многих ваших других примеров ответ часто бывает просто «потому что в конце концов вам понадобится что-то создать и сделать что-нибудь». В какой-то момент для запуска кода что-то должно быть фактической реализацией. В этом случае это библиотека файловой системы (в дополнение к библиотеке C # Telastyn в списке, есть os в Python и библиотеки файлов, связанных с Java (в java.io и java.nio ). Добавление другого слоя абстракции isn ' t сделать что-нибудь в приведенных вами примерах лучше .

В процессе принятия решений идет процесс балансировки того, следует ли использовать какой-то тип абстракции. Насколько сложнее это поддерживать код? (как обсуждалось Mason Wheeler ). Насколько проще это сделать, написав код? Являются ли преимущества, которые я ожидаю получить от этого, действительно оправдывают дополнительное время, необходимое для его внедрения? И, возможно, самый важный вопрос: действительно ли я ожидаю, что здесь будет более 1 реализации?

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

ответил Eric Hydrick 27 SatEurope/Moscow2014-12-27T02:34:03+03:00Europe/Moscow12bEurope/MoscowSat, 27 Dec 2014 02:34:03 +0300 2014, 02:34:03

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132