Pull to refresh

Comments 38

Вам понадобится логика, комбинаторика, теория множеств, все виды дискретной математики, теория графов, теория вычислимости, формальные грамматики, лямбда-исчисление, формальная семантика, топология, теории типов, теория чисел, группы, кольца, поля, категории.
Где это больше пригождается — в бэкенде или фронтенде?
А современное программирование ограничено веб-сервисами?
Ну, если вы собрались разрабатывать LLVM backend/frontend… то весь список придется держать в активной памяти.
Поймите правильно. Я ни в коем разе не против изучения математики. На редкость полезная по жизни штука. Но, если уж на то пошло, в плане полезности математики профессия программиста, как мне кажется, не сильно отличается от других профессий. Например, химика, социолога, ландшафтного дизайнера, менеджера по закупкам. То есть можно быть на редкость успешным программистом, напрочь при этом забыв, что такое логарифм. А про группы и кольца вообще ничего отродясь не знать. И быть, повторюсь, при этом на редкость успешным.

Во времена, когда компьютер был вычислительной машиной, он был про математику. Тогда, конечно, без теории чисел и формальных грамматик лучше было даже не соваться. Теперь компьютер является средством коммуникации между людьми, и поэтому на первое место выходит то, что называется soft skills. Какой смысл будет от того, что программа является шедевром с точки зрения теории типов, если разработчик напрочь лишён чуйки по части нужд пользователей, и поэтому программой всё равно никто не будет пользоваться?

Кстати, чтобы дважды не вставать. Вопрос, на который никто из программистов-математиков не может дать ответа, который не противоречил бы наблюдаемым явлениям. Вот у нас есть ООП. Инкапсуляция, наследование, полиморфизм. В чём математическая основа этой штуки? Теория множеств? Или группы? Или категории? Как базовые понятия (объект, класс, атрибут, метод) мэппятся на математику? Вот реляционная алгебра, например — прямой потомок исчисления предикатов. А ООП — чей потомок?
Не торопитесь с ответом. Вопрос более чем каверзный.
Вот у нас есть ООП. Инкапсуляция, наследование, полиморфизм. В чём математическая основа этой штуки? Теория множеств? Или группы? Или категории? Как базовые понятия (объект, класс, атрибут, метод) мэппятся на математику?

Теория типов.
Есть доступное простым смертным описание этой штуки? Чтобы по-нашему, по рабоче-крестьянски?

И что, кстати, эта теория говорит насчёт старого холивара про множественное наследование? Кошер оно или не кошер?
Есть доступное простым смертным описание этой штуки?
ИМХО в Википедии четко и доступно:

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

Теория типов — математически формализованная база для проектирования, анализа и изучения систем типов данных в теории языков программирования (раздел информатики). Многие программисты используют это понятие для обозначения любого аналитического труда, изучающего системы типов в языках программирования. В научных кругах под теорией типов чаще всего понимают более узкий раздел дискретной математики, в частности λ-исчисление с типами.

Современная теория типов была частично разработана в процессе разрешения парадокса Рассела и во многом базируется на работе Бертрана Рассела и Альфреда Уайтхеда «Principia mathematica»[1].


Как видим ноги растут из теории множеств (как и у др. теорий современной математики). Мне как программисту в первую очередь вспоминаются классические книги:
  • Дал У., Дейкстра Э., Хоор К., Структурное программирование. М.:«Мир», 1975.
  • Н.Вирт, К. Иенсен. Паскаль. Руководство для пользователя и описание языка. М.: Финансы и статистика, 1982 ;
  • Алгоритмы + структуры данных = программы. М.: Мир, 1985;

С точки зрения этого подхода классы ООП естественным образом выглядят, как расширения паскалевских записей (type record) начиная с turbo-Pascal 5.5 и Think Pascal до Delphi 7. (Более поздние версии Дельфи могут больше, но ИМХО цена за это — частичная утрата первоначальной стройности).
про множественное наследование

ИМХО очень яркая вспышка холивара произошла в процессе принятия спецификации CORBA, т.к. у OMG был принцип достижения полного консенсуса среди участников, а участвовали лидеры IT индустрии. Если поднять выпуски OMG First Class Newsletter, можно отследить доводы сторонников и противников, вполне разумные ИМХО попытки примерить множественное наследование с теорией типов.

Паскаль возник как обучающий язык, эта особенность перешла и в ОО Паскаль, где ради теоретической стройности множественное наследование не поддерживалось. Си, напротив, возник как практический язык, у которого на первом месте была эффективность и гибкость. С++ постарался перенять эти цели. Лично я сторонник паскалевского подхода и считаю, что принципы защитного программирования (в том числе и строгости типизации данных) для современного ПО важнее черезмерной гибкости ЯП. Общемировая практика показывает, что обилие ненадежного ПО может привести к техногенным катастрофам с тяжелыми последствиями.
Спасибо за развёрнутый ответ.

Ну Вы, наверно, и сами понимаете, что «какая-либо формальная система» — это не совсем то, что было бы достаточно. Хотелось бы что-нибудь похожее на то, как оно принято у реальных пацанов — аксиоматику, теоремы, леммы и т.п. История возникновения и прочая лирика, конечно, интересны, но не в них соль.

Вообще, вопрос про математическую основу ООП далеко не праздный. В первую очередь, именно с концептуальными идейными недоработками я склонен связывать тот лавинообразный рост сложности (а как следствие, прожорливости, тормознутости и ненадёжности) программ. За последние 20 лет объём ОП вырос в тысячу (!!!) раз, скорострельность процессоров тоже как минимум на порядок, но по субъективным ощущениям, всё тормозит ещё сильнее. В некоторых областях (например, в отрисовке 3D-сцен) гигантский прогресс, но по части бытовой элементарщины типа формочек-кнопочек-менюшек громоздим фреймворк на фреймворк поверх ещё кучи фреймворков, и конца-краю этому не видно.

Казалось бы, задача ORM (object-relational mapping) должна быть проще пареной репы, но оказывается, решения «в общем виде» вообще не существует. Реляционные дела у нас на строгой математической основе (исчисление предикатов), а объектные, по сути, являются набором шаманских практик. Прямое соответствие между математикой и шаманством протянуть без шансов.

Возвращаемся к первоначальной теме. И вот смотрите, приходит в «цех» молодой боец, изучивший и понявший кучу разнообразных экзотических исчислений, и получает в зубы GoF (паттерны ОО-проектирования). Изучай, товарищ, многообразие и конструктивные особенности шаманских бубнов.
ИМХО в первую очередь стоит упомянуть о принципиальной разнице между
сomputer science (CS) и математикой. Первая (как отметили Аллен Ньюэлл
и Герберт Саймон в своей лекции на вручении премии Тьюринга) экспериментальная наука, а вторая нет. Но математика и CS имеют области пересечения. Теория типов — одна из таких областей. Чистый мат. подход нужно искать у Рассела — см. в вики статью «парадокс Рассела». — Там не просто математика, а мат. логика, которую иногда противопоставляют обычной «недостаточно строгой» математике. Обратите внимание на секцию «Влияние на математику» — в числе прочего такое нехилое направление, как интуиционизм.

В CS, пожалуй, подход более приземленный, ближе к практике, частично инженерный. В принципе, не слишком сложную программу можно написать в машинных кодах не прибегая к явной типизации данных и к ООП. Но тут на первый план выступает человеческий фактор — человек недостаточно аккуратен, чтобы выполнять такое кодирование. Трудоемкость даже для составления небольшой программы будет запредельной. Я только хочу сказать, что многие вещи в ЯП появились не из-за объективной необходимости (не из-за свойств окружающего мира, физики, математики), а из-за свойств человеческого сознания — в частности, из-за свойства делать такие ошибки, которые исправный комп никогда не сделает.

Но всякая монета имеет оборотную сторону. Как Вы справедливо отметили, платой за всевозможные фреймворки является тормознутость. Тут ИМХО многое зависит от общей проф.культуры программиста. Почти всегда можно найти золотую середину. Но не все умеют, а многие не хотят, а хотят спихнуть работу быстрее, чтобы хоть как-то работало.

BTW интересно, что многие популярные ЯП не требуют обязательного применения ООП. Интересно, что и многие алгоритмы (не только старые, но и новые) описывают на псевдокоде без ОО. Я зачастую делаю на ООП только GUI. Нпр., когда хочу проверить собственный алгоритм.
многие вещи в ЯП появились не из-за объективной необходимости (не из-за свойств окружающего мира, физики, математики), а из-за свойств человеческого сознания — в частности, из-за свойства делать такие ошибки, которые исправный комп никогда не сделает
Даже не столько из за свойств делать ошибки, сколько из-за, скажем так, врождённой объектной ориентированности нашего мышления. Для того, чтобы о чём-то помыслить, нам нужно объявить кусок реальности отдельной дискретной сущностью и обозвать словом. То есть это не самой реальности свойственно состоять из объектов, а нашему мышлению свойственно пребывать в полном недоумении до тех пор, пока мы не смогли с некоторой устраивающей нас степенью условности поделить единую реальность на объекты.

Программирование — такая же деятельность, как и остальные. Ковыряясь в теле программы, мы не можем без выделения объектов. Если программа совсем простая, нам хватает мелкой нарезки (переменные, синтаксические конструкции), но при дальнейшем даже очень небольшом возрастании сложности возникает потребность оперировать более крупными строительными блоками. Хотя бы порезать это безобразие на процедуры и модули. И, да, структуры и классы.

Пока ООП рассматривается как способ облегчения программисту понимания его собственной программы, всё обычно в порядке. Ерунда начинается, когда ОО принимается как способ формализации предметной области. То есть той самой реальности, которая ни из каких объектов, конечно же, не состоит. Как только обстоятельства чуточку меняются (мы называем это уточнением постановки задачи) вполне вероятно, что тот способ декомпозиции реальности, который нам секунду назад казался незыблемой вечной истиной, летит ко всем чертям. Если та декомпозиция уже была воплощена в иерархию классов, начинаем всё перепиливать. Или, если на это нет бюджета, расставлять миллион костылей.
Не знаю кто как спасается, но лично для себя я в качестве меньшего зла принял простое правило (которое, кстати, успешно заменяет все четыре принципа SOLID): никогда (от слова «совсем») не наследовать бизнес-сущности от других бизнес-сущностей. Тоже, конечно, не сахар с мёдом, но от многих бед спасает.
Спасибо! Очень интересный получается разговор. Чтобы он был конкретнее, предложу в качестве примера собственный код. Там я поставил перед собой задачу показать различные способы представления графов, и ИМХО ООП для такой задачи очень подходит. А вот в послужившей отправной точкой программе игры "Из мухи слона" (МС) я не использовал ООП для выбранного представления графа (только для GUI). Как по-Вашему, это согласуется с принципами ООП типа SOLID? ;)
То есть это не самой реальности свойственно состоять из объектов, а нашему мышлению свойственно пребывать в полном недоумении до тех пор, пока мы не смогли с некоторой устраивающей нас степенью условности поделить единую реальность на объекты.
Делая программу МС, я не задумывался над выделением объектов «буква», «слово». Чаще просто определял по мере надобности локальные переменные. «Объект» Граф — это просто несколько массивов: один — двумерная матрица смежности с элементами Булева типа, где элемент (i,j) равен истине, если существует ребро между вершинами i и j, другой массив — вектор, где компонента i — слово (стандартная строка string) из словаря существительных русского языка, и т.д. Все операции осуществлял через простые процедуры и функции, но не методы ООП. ИМХО через ООП все то же самое выглядело бы академичнее, но код был бы большего размера, а выигрыша никакого. (Тем более, что не преследовал цели публиковать код).
Могут такие примеры спасти молодых бойцов от шаманских бубнов?
Наворачивать иерархии служебных (инструментальных) классов — да на здоровьечко. То есть цепочка «TObject-TGraph-TDirectedGraph-...-TDirectedGraphWithBlackJackAndWhores» — совершенно нормально.
В моём правиле говорится о бизнес-сущностях. То есть тех, которые имеют какое-то отношение не только к внутренеей кухне, но и к грешному реальному миру.

Могут такие примеры спасти молодых бойцов от шаманских бубнов?
Молодых бойцов от шаманских бубнов, увы, не спасёт ничто :(

Когда-то давным-давно, лет 15 назад, у меня была фантазия о том, что очень не хватает возможности многократно типизировать объекты. То есть, например, объект Вася пусть будет типа «ТМужчина+ТСантехник+ТАлкаголик», объект Маня будет «ТЖенщина+ТУборщица+ТАлкаголик». С динамической доклассификацией/расклассификацией на лету. Вот в такой интерпретации мы бы получали очень неплохое идейное соответствие теории множеств. То есть классы у нас были бы множествами, а объекты — их элементами.
многократно типизировать объекты. То есть, например, объект Вася пусть будет типа «ТМужчина+ТСантехник+ТАлкаголик», объект Маня будет «ТЖенщина+ТУборщица+ТАлкаголик».

Интерфейсы?

Как только обстоятельства чуточку меняются (мы называем это уточнением постановки задачи) вполне вероятно, что тот способ декомпозиции реальности, который нам секунду назад казался незыблемой вечной истиной, летит ко всем чертям. Если та декомпозиция уже была воплощена в иерархию классов, начинаем всё перепиливать. Или, если на это нет бюджета, расставлять миллион костылей.
Увы, это общая проблема моделирования. Модель всегда минимизирует свойства прототипа, т.е. отбираются только значимые свойства. Нпр., модель самолета для испытаний в аэродинамической трубе может быть сделана из монолитного куска дерева и не иметь двигателя, иллюминаторов, шасси и т.д. Для каких-то других испытаний придется выбросить деревяшку и изготовить другую модель, отражающую другие свойства прототипа. Про методологию мат.моделирования очень интересные книги:
  • Блехман И.И., Мышкис А.Д., Пановко Я.Г. Механика и прикладная математика. Логика и особенности приложений математики.
  • Мышкис А. Д., Элементы теории математических моделей. Изд. 3-е, исправленное. М.: КомКнига, 2007

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

При исследовании различных гипотез может оказаться, что две модели одного прототипа противоречат друг-другу. Тогда единая иерархия классов будет невозможна. Т.о. ИМХО ООП мощный и полезный инструмент, но каждый инструмент не универсален и имеет границы применимости, нпр., отверткой не надо забивать гвозди, а молотком саморезы. Когда без ООП можно обойтись — лучше ИМХО обойтись, если это не усложнит программу. (Disclaimer. Как и ко всем общим рекомендациям, к этой надо отнестись с большой осторожностью!)
UFO just landed and posted this here
Начинается всё с попытки вообще формализовать, что такое программа на языке программирования. Ну там, что значит её выполнение, например.
Именно программа? — что такое программа на языке программирования, а не что такое алгоритм?
UFO just landed and posted this here
Ага, спасибо. Именно про оттенки я и спросил. Нпр., доказывают корректность алгоритма (если доказывают, иначе называют «эвристическим» :), оценивают его теоретическую вычислительную сложность для наихудшего случая и т.д.
UFO just landed and posted this here
Глянул. Судя по всему, интересная книжка. Почитаю на досуге. Спасибо.
То есть можно быть на редкость успешным программистом, напрочь при этом забыв, что такое логарифм.

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

это базовое понятие обычно и объясняется по месту в объяснялках по О нотации, так что знание логарифма тут так себе…

Что значит знание логарифма так себе? Вы же сами и говорите, что объясняется по месту при объяснении О нотации. И если программист не понимает откуда берется логарифм, то у него не все в порядке с логикой, потому что это очевидно. Это не высшая математика, почти как сложение и умножение, только в программировании.
Вот у нас есть ООП. Инкапсуляция, наследование, полиморфизм. В чём математическая основа этой штуки? Теория множеств? Или группы? Или категории? Как базовые понятия (объект, класс, атрибут, метод) мэппятся на математику? Вот реляционная алгебра, например — прямой потомок исчисления предикатов. А ООП — чей потомок?

Это аргумент против ООП, не против математики.

На фронтенде вам ничего не пригодится. Тыкайте себе кнопочки на здоровье. В среднем даже будет работать.
Как минимум надо бы в типизацию уметь на фронтенде.
Излишний формализм часто бывает опасен.
Кстати, если уж речь зашла про тесты, то надо было бы добавить ещё много чего из жизненного цикла ПО. Например, мониторинг, анализ, совершенствование кода.
Про математику нет единого мнения, см., нпр., этот опрос — вопрос: «Роль математики для информатики в школе высокая».

ИМХО математика очерь нужна программисту, но в списке статьи топология — это непонятно, где топология в программировании, указана теория графов и там топология (не геометрия) — это Ok — нужно, но мат. дисциплина топология, где ее практически применить в кодах?

PS Не указана теория сложности вычислений. М.б. я просмотрел, м.б. иначе названа?
Если ваш друг прочитал интересную статью и рассказал вам об этом, вы просто сэкономили много своего времени, потому что он дал вам обработанные, кристаллизованные знания.

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

Возьмите хорошую книгу и решайте олимпиадные задачи онлайн.

Только не стоит злоупотреблять — реальные задачи часто расходятся с олимпиадным программированием по используемым инструментам, по масштабу и критериям оценки. В частности «чистые» олимпиадники могут писать такую жуть, что там черт ногу сломит. Работает хорошо, а поддерживать этот код невозможно.

От себя бы добавил, что полезно объяснять изучаемый материал другим людям. В разных форматах — это и помощь начинающим, и ответы на SO или Тостере, статьи и.т.д. Это заставляет структурировать информацию в голове, вопросы от других людей указывают на пробелы в знаниях, а еще статьи позволяют освободить мозг для новой информации — это очень помогает, особенно со сложными темами, которые нужны не каждый день.
Опыт учебного центра, который работал в нашем здании и который периодически привлекал нас к курсам показывает: из 10 человек, которые хотят стать программистами, ими становятся в среднем человека 4, хорошими программистами — 2.
Остальные понимают, что это не их и постепенно уходят в смежные области: анализ, администрирование, управление проектами.
Нужно это помнить и не стараться «стать программистом любой ценой».
очень полезно программистам кроме вышеперечисленного изучение языков, особенно английского.
Scheme, Smalltalk, Eiffel, ML… Я никогда не понимал зачем учить мёртвые языки.
Лучше учить те языки с которыми можно идти в продакшн. Java, C#, C++, Python… При помощи одного из этих языков можно идти в реальный продакшн, писать, развиваться.

Математика это хорошо когда ты занимаешься высоконагруженными вычислениями, но для многих областей она практически не нужна, например, веб разработка.
Не холивара ради, а исключительно из любопытства — чем все-таки автору не угодил Python как первый язык?

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

В идеале это должно происходить еще в школе, но и в университете полно людей, которые только издали видели Паскаль и ничего не поняли.

Клевое — это, конечно, очень субъективное понятие, но, например, какая-то примитивная графика обычно заходит на ура — летающие по экрану кружочки, крестики-нолики, исполнитель-черепашка. Веб тоже хорошо идет.
Ардуино, где можно легко помигать светодиодом или покрутить моторчиком.

Еще крайне желательно, чтобы рабочая среда была дружелюбной и настраивалась легко и быстро.

Python этим требованиям вроде бы вполне удовлетворяет. А вот как с этим у Scheme и Smalltalk — я вообще не в курсе, к сожалению.

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

Подозреваю, что у предложенных вами языков с этим похуже.
Автор статьи сразу же уточняет, что советы его имеют субъективный характер: «пост состоит из некоторых полезных советов, которые я хотел бы услышать, когда мне было 18 лет». Поэтому критиковать положения из статьи стоит умеренно. В конце концов, если вы не последуете этим советам, то не станете преподавателем компьютерных наук, а вашу книгу по низкоуровневому программированию не будут рекламировать на Amazon. Только и всего. К счастью в информатике довольно широких дорог и узких тропинок для всех. Но лично мне интересен опыт автора и его путь в программировании.

Видно, что автор находится в стадии очарования функциональным и доказательным программированием. Ни вижу в этом ничего плохого. Но вот интересный момент: что предлагается выбрать в качестве первого языка. Scheme/Smalltalk — это языки компьютерных первопроходцев-экспериментаторов. Они олицетворяют тот подход в программировании, который позволяет эволюционно и итеративно разрабатывать программы. Эти языки не сковывают программиста правилами, а дают возможность уточнять задачу и алгоритмы прямо в процессе реализации. Совсем другое дело — Eiffel и ML. Замечательные языки, но нацелены они на совсем иной подход к разработке ПО. Предполагается, что в уме у нас уже есть формализованная модель задачи и мы описываем ее со всеми необходимыми ограничениями, которые не позволят получить некорректный результат. На мой взгляд, начинающему лучше иметь дело с языками Scheme/Smalltalk, которые не будут к нему и его не до конца оформленным идеям слишком строги. Другой вариант — какой-то язык с постепенной типизацией.

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

Полностью разделяю призыв автора знакомиться с разными подходами к программированию, с разными языками. Тут можно привести известные слова А. Перлиса: «A language that doesn't affect the way you think about programming, is not worth knowing».

Приятно, что упомянут и пункт по конструированию DSL — очень близкая мне тема. Вот только с выбором конструкторов не могу согласиться (JetBrains MPS, XText). Я бы предложил в первую очередь Stratego/XT.

И последнее. Автор неслучайно говорит о страсти к программированию. Страсть, любовь к написанию программ это те факторы, которые позволяют мириться с рутиной, которой в нашей профессии хоть отбавляй. Если вы думаете заняться программированием только лишь ради популярности профессии, ради заработка, то… есть способы заработать проще. Высиживать перед экраном долгие часы, пребывать в угнетенном состоянии, когда что-то не работает или снова нужно изучать новые подходы и технологии — все это легко преодолевается, только если у вас есть страсть, если вы действительно любите разрабатывать программы.

Для Питона, увы, нет эквивалента SICP.

Почему вы так думаете?
Вот по ссылке заявлена книга SICP in Python: https://wizardforcel.gitbooks.io/sicp-in-python/content/index.html
Темы в ней, правда, немного переставлены. Странно было бы ждать полного эквивалента от книги на другом языке.

Спасибо за ссылку, не встречал этого текста. По беглому просмотру делаю следующий вывод. Это не эквивалент, то есть не нечто равноценное оригинальному SICP. Больше похоже на дословный перевод стихотворения без соблюдения рифм и подбора метафор. Кроме того, здесь далеко не весь материал SICP, самые интересные темы отсутствуют.

Выбор именно Scheme для оригинального SICP являлся определяющим с точки зрения методики преподавания: это «пластилиновый» язык, голое синтаксическое дерево. С одной стороны, конкретный синтаксис не затеняет детали реализаций алгоритмов, а с другой — Scheme дает гибкость в исследовании самых разных стилей программирования.

Повторюсь, учебника для Питона, который учит решать задачи в хорошем питоновском стиле я пока не встретил. В этом отношении мне понравился подход П. Норвига: norvig.com/python-lisp.html
Обратите внимание на пример с генератором случайных фраз. Норвиг сначала приводит реализацию на Питоне такой, какой бы написал ее Лисп-программист. Затем он показывает более изящный вариант — более идиоматический, характерный для Питона.
Какое счастье, что я учил программирование, когда о нем еще никто толком не знал, никто не давал мне подобных советов и я занимался всем подряд — тем, что мне нравилось.

Бедные современные студенты, с молодости попавшие под пяту необходимости.
Sign up to leave a comment.

Articles