Вы по ходу дела плавно подменили первоначальную проблему "сложно уникально адресовать два класса с одинаковым названием, не привязываясь к файлам, в котором они определены" другой — "мне нужно импортировать два класса с одинаковым названием и это не решается алиасами" :)
Дело в том, что в PHP-проекте я могу написать:
$init = new \Doctrine\DBAL\Event\Listeners\MysqlSessionInit()
без того, чтобы использовать import или require. При этом я не должен знать о том, в каком каталоге находится файл, в котором находится исходный код. Именно потому, что в PHP/Java/TypeScript/… есть директива namespace. А в JS/Python этой директивы нет, вы её никогда не использовали и не понимаете для чего она вообще может быть нужна. Если вам она не нужна, то это говорит только о том, что вы ещё не достигли своего предела сложности в JS/Python.
Я не программирую на TypeScript, а в JS нет namespace'ов (поэтому они не выручат). Что касается PHP, то вот два класса с одинаковым именем Configuration, конфликт которых "разводят" namespace'ы (оба класса, что характерно, находятся в файлах Configuration.php):
Для того, чтобы создать объекты этих классов в современном PHP-приложении мне достаточно знать их полные имена, все остальное делает менеджер зависимостей (autoloading).
Вы правильно сказали — "не попадают в глобальный скоуп". В JS вообще нет namespace'ов в смысле логической группировки элементов кода. Есть scope. Именно поэтому на JS'е сложно писать сложные проекты — сложно уникально адресовать два класса с одинаковым названием, не привязываясь к файлам, в котором они определены. А в PHP можно. И в Java можно. И в Typescript можно (если я правильно понял).
Пространства имён не привязаны к языку. В Java нет жестких требований по расположению файлов — вы указываете их местоположение в CLASSPATH при запуске приложения.
И пространства имён не являются обязательной фичей для достижения "максимальной сложности приложений". Я пытался донести мысль, что пространство имён при прочих равных условиях (например, язык и квалификация разработчика) позволяют создавать более сложные приложения, чем без них. Вы можете писать на PHP без использования namespace, некоторые до сих пор так и делают. Но в таких пакетах, как Zend2, Symfony, Laravel — используются namespaces.
Кстати, в Yii и CodeIgniter, к моему удивлению, не используют пространства имён. В результате в Yii имена файлов выглядят так:
А в CodeIgniter так:
Обратите внимание на префиксы в названиях файлов — разрабы вынуждены обеспечивать уникальность имени каждого файла в пределах проекта (по сути, вручную, не используя средств языка, вводят пространства CDb и DB_). Да, для 1000 файлов они выкрутятся (какой ценой?), а для 300 млн.?
Если вдруг решите попрограммировать на PHP, не начинайте с Yii и CodeIgniter ;)
В вашем проекте папки и файлы организованы так, в моём — по-другому, у кого-то — по третьему. Посмотрите содержимое файла autoload_namespaces.php, фрагмент которого я привёл в разделе "Автозагрузка кода". В нём видно, как файловая система каждого модуля (а сторонний модуль в вашем проекте с вашими правилами для кого-то является собственным проектом со своими правилами) монтируется в единую логическую структуру кода в вашем проекте. Вот, например, исходники модулей находятся в таких подкаталогах внутри каталога ./vendor вашего проекта:
./magento/zendframework1/library
./phpspec/prophecy/src
./phpmd/phpmd/src/main/php
Но вы не заморачиваетесь путями к исходникам, а просто пишете в своём коде:
$center = new \Prophecy\Call\CallCenter();
Поиск файла с исходниками автозагрузчик autoload.php выполнит самостоятельно, на основании привязки пространства \Prophecy\* к каталогу ./vendor/phpspec/prophecy/src.
Если ваш проект собран при помощи PHP Composer, то ваш код не изменится, если Konstantin Kudryashov (автор модуля phpspec/prophecy) захочет изменить структуру своего модуля и перенести исходники в своём модуле в каталог, например, ./phpspec/prophecy/src/main/php. Он просто укажет в composer.json своего модуля:
С появлением autoloader'a PHP-разработчики перестали держать в голове файловую структуру своего проекта (и файловую структуру сторонних модулей, используемых в своём проекте) и стали держать логическую структуру кода (которая гораздо проще).
Пространство имён не нужно, если на компьютере в проекте хранится участвует 5-10 файлов разработчиков со своими модулями. Но если на компьютере в проекте хранится участвует 1000 файлов разработчиков со своими модулями, то пространство имён становится более актуальным.
Похоже, я ввёл вас в заблуждение, пытаясь продемонстрировать работу "пространства имён" на примере библиотек.
namespace в PHP и package в Java относятся к исходному коду, а не к библиотекам.
Попробую запутать вас ещё больше. Всем известные интернетовские домены — это пример применения namespace'ов на практике. Две разные библиотеки два разных домена с именем mail одновременно существуют в одном проекте интернете именно потому, что они принадлежат двум разным пространствам имён:
Пространство имён — некоторое множество… созданное для логической группировки уникальных идентификаторов…
На самом деле можно в интернете проекте обойтись без доменов верхнего уровня и вообще без доменов namespace'ов и адресовать все хосты библиотеки "плоской" строкой. Это примерно то же самое, как хранить все файлы на компьютере в одном корневом каталоге. Да-да, файловая система — это тоже пример "логической группировки уникальных идентификаторов" (имён файлов) при помощи "некоторых множеств" (каталогов).
И если на компьютере хранить 5-10 файлов, то вполне резонно задаваться вопросом, а для чего мне вообще нужны каталоги? И получить вполне логичный ответ — для хранения 5-10 файлов каталоги не нужны.
Если это позволяет вам выстраивать единую структуру кода для вашего проекта и ориентироваться в ней на уровне элементов кода (классы, функции, константы, ...), а не на уровне файлов и строк, то почему бы и нет.
То есть, если вы не публикуете пакет в публичный npm, а используете его приватно, можете называть его как угодно.
Вот за то и речь. Называя как угодно свои приватные модули, мы уменьшаем себе возможность их использования в глобальных проектах. Допустим, вы сделали приватный модуль debug для своего проекта, выложили на корпоративный репозиторий и используете его в своих проектах. В какой-то момент ваша корпорация поглощает другую корпорацию и вашему IT-отделу ставится задача адаптировать их замечательные наработки в ваши. А у них такой же модуль debug используется. Вот и получаем вилы на ровном месте.
В java-мире, например, корпорация Oracle поглотила корпорацию Sun, а пакет com.oracle.json замечательно сосуществуют рядом с пакетом com.sun.net.httpserver.
А представьте, что вы бы захотели опубликовать свой приватный пакет debug для открытого использования?
Ничто не мешает генерировать ссылку типа такой: npm-module-name/path/to/file.js:123.
Это всё равно привязка к тексту в файле, а не к логической структуре кода (константа, метод, класс, ...). Адресация поплывет при изменении кол-ва строк в файле.
Имена классов в JS-модулях локальные, придумывать уникальные имена в рамках всего проекта не надо.
Вполне возможно, что мой прогноз — "пальцем в небо".
Файлы из своего проекта можно импортировать только через относительные пути.
Этот коммент замечательно иллюстрирует сказанное в пункте "Автозагрузка кода". Нам приходится отталкиваться от файловой структуры, если нам сложно отталкиваться от структуры кода.
Согласен. Даже есть подозрение, что если бы человек слил уязвимость на сторону и ее начали бы эксплуатировать, то эту уязвимость законопатили бы значительно быстрее. Особенно, если тоннами начали сливаться деньги.
А универсального решения, устраивающего всех, нет. Если работаешь в разнородной среде то ради униформности чего только не приходится делать. Это вы ещё на фронт не залазили.
С точки зрения backend-разработчика человеческого пользователя нет всегда. Но это ограниченная точка зрения.
С точки зрения forntend-разработчика (в частности, разработчика SPA) человеческий пользователь есть слишком часто, чтобы его игнорировать. Разделение ошибок на 500-е (т.е., любые ошибки, не предусмотренные логикой операции, которые произошли в момент выполнения зпроса на сервере) и на ошибки бизнес-логики, зависящие от конкретной запрошенной операции (200-е с необходимостью анализа содержимого поля "ошибка") позволяют запускать на клиенте сценарии решения ошибочной с точки зрения бизнес-логики ситуации с использованием полученных с сервера данных.
Другими словами, 500-я ошибка — это всегда тупиковая ошибка. Ее обработка и на неинтерактивном клиенте и на интерактивном одинакова — логируем / показываем пользователю сообщение, что все плохо. Код ошибки в 200-м ответе сигнализирует, что выполнение запрошенной операции на сервере пошло по одному из предусмотренных разработчиками сценариев, не обеспечивающих успешного завершения в силу каких-то условий. В этом случае пользователь (интерактивный) или программа (неинтерактивный) может выполнить некоторые дополнительные действия, после чего повторить операцию.
То есть, если сценарий выполнения операции предусматривает возможность дублирования ИНН и имеются рекомендации для пользователя, что нужно сделать в данном случае — это ошибка бизнес-логики (код 200). Если на сервере при добавлении записи в БД произошла ошибка из-за того, что в таблице на поле ИНН повешен ключ уникальности, а записывались данные с повторяющимся значением ИНН, которая перехватилась и обернулась в типовое сообщение об ошибке на уровне REST framework'а, потому что разраб сервиса даже не предполагал такого варианта — это 500-я ошибка.
Почему не передавать все ошибки через 500-й код? Потому что в таком случае смешивают обычные ошибки (как правило выполнение операции невозможно по независящим от клиента обстоятельствам) и ошибки бизнес-логики (зачастую операция возможна при внесении некоторых изменений в данные или предварительном выполнении других операций), очень сильно привязанные к контексту текущих выполняемых действий (т.е. к тому же контексту, в котором на клиенте происходит дальнейшая обработка данных, полученных с сервера в результате успешного завершения операции с кодом 200).
Есть мнение, что ошибки валидации входных данных не являются ошибками, как таковыми — это предусмотренный сценарий взаимодействия. Эту точку зрения можно распростанить и на ошибки бизнес-логики, предусмотренные разработчиками сервисов. Все остальное — настоящие ошибки, 500-й код, окончательный тупик.
но оибку в бизнес логике, возврещается HTTP код 200 и документ с полем ошибка, описанием ошибки и кодом ошибки (код ошибки не HTTP, а самой системы).
Вот за то коллега evgenyk и говорил. Если ошибка бизнес-логики, значит пользователь что-то сделал не так, как предусматривалось разработчиками, и ему нужна дополнительная информация, чтобы он сам мог разрулить ситуацию (если она разруливаемая), которая через состояния HTTP-статуса не передается. Очень редко, когда пользователь остается доволен, видя на экране надпись "Ошибка 500. Обратитесь в службу поддержки".
Я понимаю, откуда ноги растут у вашего "и клиенту нужно каждый раз парсить содержимое поле "ошибка". Спасибо, нет." — вы серверный разработчик с соответствующим взглядом на разработку.
А тело ответа — оно зачем в таком случае? Либо его тоже нужно парсить, и тогда ваше "Спасибо, нет" неуместно, либо его парсить не нужно и тогда, согласно старику Оккаму, неуместно само тело. Вот это и улыбнуло.
Т.е., "код возврата" — это HTTP Status, в котором не предусмотрены ошибки бизнес-логики. Я правильно понимаю, что вы, как клиент, предпочитаете в случае ошибки на уровне бизнес-логики (например, "клиент с таким ИНН уже есть") получить ответ от сервера со статусом 200?
Вы по ходу дела плавно подменили первоначальную проблему "сложно уникально адресовать два класса с одинаковым названием, не привязываясь к файлам, в котором они определены" другой — "мне нужно импортировать два класса с одинаковым названием и это не решается алиасами" :)
Дело в том, что в PHP-проекте я могу написать:
без того, чтобы использовать
importилиrequire. При этом я не должен знать о том, в каком каталоге находится файл, в котором находится исходный код. Именно потому, что в PHP/Java/TypeScript/… есть директиваnamespace. А в JS/Python этой директивы нет, вы её никогда не использовали и не понимаете для чего она вообще может быть нужна. Если вам она не нужна, то это говорит только о том, что вы ещё не достигли своего предела сложности в JS/Python.Что такое
doctrine/DBALиdoctrine/ORM? Каталог, файл или некоторая строковая метка для поиска пути к исходникам по некоторому алгоритму?Я не программирую на TypeScript, а в JS нет namespace'ов (поэтому они не выручат). Что касается PHP, то вот два класса с одинаковым именем
Configuration, конфликт которых "разводят" namespace'ы (оба класса, что характерно, находятся в файлахConfiguration.php):Для того, чтобы создать объекты этих классов в современном PHP-приложении мне достаточно знать их полные имена, все остальное делает менеджер зависимостей (autoloading).
Вы правильно сказали — "не попадают в глобальный скоуп". В JS вообще нет namespace'ов в смысле логической группировки элементов кода. Есть scope. Именно поэтому на JS'е сложно писать сложные проекты — сложно уникально адресовать два класса с одинаковым названием, не привязываясь к файлам, в котором они определены. А в PHP можно. И в Java можно. И в Typescript можно (если я правильно понял).
Сможет. Если прописать в
./vendor/composer/autoload_classmap.phpПространства имён не привязаны к языку. В Java нет жестких требований по расположению файлов — вы указываете их местоположение в CLASSPATH при запуске приложения.
И пространства имён не являются обязательной фичей для достижения "максимальной сложности приложений". Я пытался донести мысль, что пространство имён при прочих равных условиях (например, язык и квалификация разработчика) позволяют создавать более сложные приложения, чем без них. Вы можете писать на PHP без использования namespace, некоторые до сих пор так и делают. Но в таких пакетах, как Zend2, Symfony, Laravel — используются namespaces.
Кстати, в Yii и CodeIgniter, к моему удивлению, не используют пространства имён. В результате в Yii имена файлов выглядят так:
А в CodeIgniter так:
Обратите внимание на префиксы в названиях файлов — разрабы вынуждены обеспечивать уникальность имени каждого файла в пределах проекта (по сути, вручную, не используя средств языка, вводят пространства
CDbиDB_). Да, для 1000 файлов они выкрутятся (какой ценой?), а для 300 млн.?Если вдруг решите попрограммировать на PHP, не начинайте с Yii и CodeIgniter ;)
В вашем проекте папки и файлы организованы так, в моём — по-другому, у кого-то — по третьему. Посмотрите содержимое файла
autoload_namespaces.php, фрагмент которого я привёл в разделе "Автозагрузка кода". В нём видно, как файловая система каждого модуля (а сторонний модуль в вашем проекте с вашими правилами для кого-то является собственным проектом со своими правилами) монтируется в единую логическую структуру кода в вашем проекте. Вот, например, исходники модулей находятся в таких подкаталогах внутри каталога./vendorвашего проекта:Но вы не заморачиваетесь путями к исходникам, а просто пишете в своём коде:
Поиск файла с исходниками автозагрузчик
autoload.phpвыполнит самостоятельно, на основании привязки пространства\Prophecy\*к каталогу./vendor/phpspec/prophecy/src.Если ваш проект собран при помощи PHP Composer, то ваш код не изменится, если Konstantin Kudryashov (автор модуля
phpspec/prophecy) захочет изменить структуру своего модуля и перенести исходники в своём модуле в каталог, например,./phpspec/prophecy/src/main/php. Он просто укажет вcomposer.jsonсвоего модуля:и при сборке или обновлении вашего проекта в следующий раз в карту пространства имен
autoload_namespaces.phpзапишется так:С появлением
autoloader'a PHP-разработчики перестали держать в голове файловую структуру своего проекта (и файловую структуру сторонних модулей, используемых в своём проекте) и стали держать логическую структуру кода (которая гораздо проще).Пространство имён не нужно, если
на компьютерев проектехранитсяучаствует 5-10файловразработчиков со своими модулями. Но еслина компьютерев проектехранитсяучаствует 1000файловразработчиков со своими модулями, то пространство имён становится более актуальным.Похоже, я ввёл вас в заблуждение, пытаясь продемонстрировать работу "пространства имён" на примере библиотек.
namespaceв PHP иpackageв Java относятся к исходному коду, а не к библиотекам.Попробую запутать вас ещё больше. Всем известные интернетовские домены — это пример применения namespace'ов на практике.
Две разные библиотекидва разных домена с именемmailодновременно существуют водном проектеинтернете именно потому, что они принадлежат двум разным пространствам имён:Пространство имён — некоторое множество… созданное для логической группировки уникальных идентификаторов…
На самом деле можно в интернете
проектеобойтись без доменов верхнего уровня и вообще без доменовnamespace'ови адресовать все хостыбиблиотеки"плоской" строкой. Это примерно то же самое, как хранить все файлы на компьютере в одном корневом каталоге. Да-да, файловая система — это тоже пример "логической группировки уникальных идентификаторов" (имён файлов) при помощи "некоторых множеств" (каталогов).И если на компьютере хранить 5-10 файлов, то вполне резонно задаваться вопросом, а для чего мне вообще нужны каталоги? И получить вполне логичный ответ — для хранения 5-10 файлов каталоги не нужны.
Если это позволяет вам выстраивать единую структуру кода для вашего проекта и ориентироваться в ней на уровне элементов кода (классы, функции, константы, ...), а не на уровне файлов и строк, то почему бы и нет.
Спасибо за развёрнутый коммент, коллега.
Вот за то и речь. Называя как угодно свои приватные модули, мы уменьшаем себе возможность их использования в глобальных проектах. Допустим, вы сделали приватный модуль
debugдля своего проекта, выложили на корпоративный репозиторий и используете его в своих проектах. В какой-то момент ваша корпорация поглощает другую корпорацию и вашему IT-отделу ставится задача адаптировать их замечательные наработки в ваши. А у них такой же модульdebugиспользуется. Вот и получаем вилы на ровном месте.В java-мире, например, корпорация Oracle поглотила корпорацию Sun, а пакет
com.oracle.jsonзамечательно сосуществуют рядом с пакетомcom.sun.net.httpserver.А представьте, что вы бы захотели опубликовать свой приватный пакет
debugдля открытого использования?Это всё равно привязка к тексту в файле, а не к логической структуре кода (константа, метод, класс, ...). Адресация поплывет при изменении кол-ва строк в файле.
Вполне возможно, что мой прогноз — "пальцем в небо".
Этот коммент замечательно иллюстрирует сказанное в пункте "Автозагрузка кода". Нам приходится отталкиваться от файловой структуры, если нам сложно отталкиваться от структуры кода.
Вы живёте в страшном мире, коллега. Вас окружают идиоты с торчащими из глаз карандашами и вокруг всё в крови. Сюрненько.
Согласен. Даже есть подозрение, что если бы человек слил уязвимость на сторону и ее начали бы эксплуатировать, то эту уязвимость законопатили бы значительно быстрее. Особенно, если тоннами начали сливаться деньги.
Может быть потому, что опытные рекламщики не смогли донести информацию о своей полезности до потенциального потребителя?
А универсального решения, устраивающего всех, нет. Если работаешь в разнородной среде то ради униформности чего только не приходится делать. Это вы ещё на фронт не залазили.
С точки зрения backend-разработчика человеческого пользователя нет всегда. Но это ограниченная точка зрения.
С точки зрения forntend-разработчика (в частности, разработчика SPA) человеческий пользователь есть слишком часто, чтобы его игнорировать. Разделение ошибок на 500-е (т.е., любые ошибки, не предусмотренные логикой операции, которые произошли в момент выполнения зпроса на сервере) и на ошибки бизнес-логики, зависящие от конкретной запрошенной операции (200-е с необходимостью анализа содержимого поля "ошибка") позволяют запускать на клиенте сценарии решения ошибочной с точки зрения бизнес-логики ситуации с использованием полученных с сервера данных.
Другими словами, 500-я ошибка — это всегда тупиковая ошибка. Ее обработка и на неинтерактивном клиенте и на интерактивном одинакова — логируем / показываем пользователю сообщение, что все плохо. Код ошибки в 200-м ответе сигнализирует, что выполнение запрошенной операции на сервере пошло по одному из предусмотренных разработчиками сценариев, не обеспечивающих успешного завершения в силу каких-то условий. В этом случае пользователь (интерактивный) или программа (неинтерактивный) может выполнить некоторые дополнительные действия, после чего повторить операцию.
То есть, если сценарий выполнения операции предусматривает возможность дублирования ИНН и имеются рекомендации для пользователя, что нужно сделать в данном случае — это ошибка бизнес-логики (код 200). Если на сервере при добавлении записи в БД произошла ошибка из-за того, что в таблице на поле ИНН повешен ключ уникальности, а записывались данные с повторяющимся значением ИНН, которая перехватилась и обернулась в типовое сообщение об ошибке на уровне REST framework'а, потому что разраб сервиса даже не предполагал такого варианта — это 500-я ошибка.
Почему не передавать все ошибки через 500-й код? Потому что в таком случае смешивают обычные ошибки (как правило выполнение операции невозможно по независящим от клиента обстоятельствам) и ошибки бизнес-логики (зачастую операция возможна при внесении некоторых изменений в данные или предварительном выполнении других операций), очень сильно привязанные к контексту текущих выполняемых действий (т.е. к тому же контексту, в котором на клиенте происходит дальнейшая обработка данных, полученных с сервера в результате успешного завершения операции с кодом 200).
Есть мнение, что ошибки валидации входных данных не являются ошибками, как таковыми — это предусмотренный сценарий взаимодействия. Эту точку зрения можно распростанить и на ошибки бизнес-логики, предусмотренные разработчиками сервисов. Все остальное — настоящие ошибки, 500-й код, окончательный тупик.
Вот за то коллега evgenyk и говорил. Если ошибка бизнес-логики, значит пользователь что-то сделал не так, как предусматривалось разработчиками, и ему нужна дополнительная информация, чтобы он сам мог разрулить ситуацию (если она разруливаемая), которая через состояния HTTP-статуса не передается. Очень редко, когда пользователь остается доволен, видя на экране надпись "Ошибка 500. Обратитесь в службу поддержки".
Я понимаю, откуда ноги растут у вашего "и клиенту нужно каждый раз парсить содержимое поле "ошибка". Спасибо, нет." — вы серверный разработчик с соответствующим взглядом на разработку.
А тело ответа — оно зачем в таком случае? Либо его тоже нужно парсить, и тогда ваше "Спасибо, нет" неуместно, либо его парсить не нужно и тогда, согласно старику Оккаму, неуместно само тело. Вот это и улыбнуло.
улыбнуло.
Т.е., "код возврата" — это HTTP Status, в котором не предусмотрены ошибки бизнес-логики. Я правильно понимаю, что вы, как клиент, предпочитаете в случае ошибки на уровне бизнес-логики (например, "клиент с таким ИНН уже есть") получить ответ от сервера со статусом 200?