В этом посте обсуждаются самые последние дополнения к javascript-библиотеке Ferrum: документация, основанная на тестах, надежная инфраструктура хэширования инфраструктуры, включая хеш-таблицы.

Прошло некоторое время с момента первоначального выпуска ferrum. Более 400 звезд на Github, сто иждивенцев и всего восемь отчетов об ошибках, несомненно, доказывают, что его функции и продуманный дизайн API обеспечивают долгожданное дополнение к библиотечному ландшафту экосистемы javascript.

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

Тем не менее, можно было бы добавить множество полезных функций; способ определения классов, более полезный для функционального программирования, или обобщение API последовательности на асинхронные последовательности — это лишь некоторые из наиболее интересных идей, которые могут быть добавлены в будущем. Не стесняйтесь прыгать и делиться своим взглядом на эти концепции; разработка звуковых API для этих вариантов использования оказывается действительно сложной задачей, поэтому некоторые комментарии будут оценены.

Другие проблемы — низкие, висячие, плоды; ждем запросов на вытягивание от всех, кто пытается отточить свои навыки функционального программирования!

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

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

Это требует большого количества документации и — поскольку слишком много текста просто трудно читать — это означает примеры!

Тесты для примеров

К сожалению, приведенные примеры — это одна из областей, в которой обещания надежности железа действительно не оправдались; некоторые примеры, приведенные в ferrum, содержали ошибки! Вы скопируете их, попытаетесь запустить пример и первым делом получите синтаксическую ошибку. Не очень гостеприимный, не очень полезный и, что удивительно, проблему, которую не так просто решить, как может показаться! Поскольку примеры являются частью документации, проверка на наличие проблем включает копирование в файл, исправление проблемы и копирование примера обратно в документацию. Процесс утомительный и подверженный ошибкам. Я очень ленивый человек, поэтому я этого не делал. Вместо этого я сделал то, что делает rust, а rust выполняет примеры как часть тестов, как и ferrum — теперь!

И если вы окажетесь в том же крайнем положении, вы тоже можете!

Я не смог найти инструмент, который тестирует примеры для Javascript, поэтому я просто создал его: ferrum.doctest — это вспомогательный инструмент, который можно использовать независимо от ferrum; он запускает тесты в вашем файле readme и в вашей документации API (поддерживая как блоки кода уценки, так и теги jsdoc@example) и генерирует файл, который можно передать в выбранную вами среду тестирования. По умолчанию создаются файлы, совместимые с mocha, но вы можете указать пользовательский шаблон, чтобы это работало с любой другой тестовой средой. Карты исходного кода позволяют легко определить, какая строка в ваших примерах приводит к ошибкам. (Хотя поддержка исходных карт в инструментах разработки на удивление несовершенна, поэтому я все еще пытаюсь найти набор инструментов разработки, который хорошо работает в этих условиях.)

Начиная с версии ferrum 1.7, все примеры тестируются с использованием ferrum.doctest, поэтому я рад сообщить, что примеры с ошибками должны остаться в прошлом!

Хеширование и хеш-таблицы

Хотя тесты документации чрезвычайно полезны, я нашел их довольно утомительными в реализации. Так много практических разработок… Чтобы добавить немного волнения (или чего-то еще странного, что я считаю захватывающим), я решил внедрить новую инфраструктуру хеширования… в то время как для некоторых из нас это означает хеш-функции!

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

Наиболее распространенным вариантом использования хеш-функций является их использование в хеш-таблицах. И теперь ferrum предоставляет один (ferrum.HashMap — посмотрите примеры, теперь они должным образом протестированы). Вкратце, хэш-карты аналогичны Картам ES6 или Объектам; они являются хранилищами ключей/значений; что отличает эти три, так это то, какие типы ключей они позволяют.

Объекты позволяют использовать в качестве ключей только строки, числа и символы.
Карта ES6 позволяет использовать произвольные объекты, но ключи должны быть идентичными. (Например, два пустых объекта будут сопоставлены с разными ключами).
HashMap допускает произвольные объекты, ключи должны быть равными, но не могут хранить символы. Два пустых объекта всегда будут отображаться на одно и то же значение!

HashMap является более мощным и в большинстве случаев лучше соответствует намерениям разработчика. Большинство проблем можно решить и с помощью обычной карты, сериализуя ваши ключи в строку, но это утомительно; в основном вы реализуете свою собственную хеш-функцию на лету, используя API, который не соответствует задачам! Поскольку HashMap реализует тот же интерфейс, что и Map, во многих случаях должно быть безопасно просто заменить HashMap, если хранимые ключи реализуют Hashable, и даже это требование можно обойти, интегрировав библиотеку хэшей объектов.

Почему бы просто не использовать объектный хэш?

Вы также можете задаться вопросом, почему объектный хэш не используется по умолчанию, учитывая, что в последние годы он был фактическим стандартом хеширования в javascript. Аргументация такая же, как и аргументация, почему ferrum предоставляет свою собственную функцию равенства: в двух словах, стандартному javascript не хватает черт, и хотя интерфейсы, такие как протокол итератора, предоставляют аналогичную функциональность, интерфейсы сами по себе имеют недостатки, такие как непригодность для использования для простые предметы. Это большая проблема, которая привела к ситуации, когда библиотеки вроде object-hash должны были предоставлять эвристику для работы со сторонними типами; эти эвристики обычно работают, но когда они не работают, вам не повезло без хорошего, чистого способа решить эту ситуацию.

Черты железа решают все эти проблемы; Используя трейты, многие функции, такие как eq(), shallowclone() или теперь hash(), могут быть реализованы как чистые, рекурсивные полиморфные функции. Громкие слова, на самом деле они просто означают, что вы можете предоставить свою собственную реализацию для ваших собственных типов и что классы можно хешировать или сравнивать, сравнивая все их поля.

Таким образом, функции в ferrum очень надежны, заставляя вас явно указывать, как они должны работать для сторонних типов. И поскольку это утомительно, ferrum спроектирован достаточно гибко, чтобы вы могли также интегрировать библиотеки с помощью эвристики, например хэша объекта. Это означает, что вы получаете лучшее из обоих миров!

Я рассматриваю возможность создания еще одной сопутствующей библиотеки — ferrum.heuristic — которая реализует эвристические расширения для всех трейтов в ferrum. Ставьте лайк этой проблеме, если хотите ускорить разработку!

Следующие шаги

Ferrum много сделал для повышения стабильности проектов, над которыми я работал в прошлом году; с тестированием документации и инфраструктурой хэширования были заполнены два больших пробела в экосистеме библиотек javascript. Две функции, которые должны были быть частью стандартной библиотеки js с самого начала, значительно упрощают вашу жизнь как разработчика.

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