Застрял из-за «зная слишком много» [закрыто]


147

Обратите внимание на дальнейшее обсуждение на http://news.ycombinator.com/item?id=4037794

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

Я помню себя некоторое время назад, моложе и, возможно, более нетерпеливым. «Я», которым я был тогда, не задумывалось бы обо всем этом - он пошел бы дальше и написал бы что-нибудь, затем переписал бы это, затем переписал бы это снова (и снова ...). «Я» сегодня более нерешительно, более осторожно.

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

Это неправильно? Это естественная эволюция, или я загнал себя в колею?

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


Ух ты. Я, честно говоря, не ожидал, что этот вопрос вызовет так много ответов. Я постараюсь подвести итог.

Причины:

  1. Паралич анализа / Из-за инженерной мысли / позолота / (любое другое «слишком много обдуманного заранее может повредить вам»).
  2. Слишком много опыта для данной задачи.
  3. Не фокусируясь на том, что важно.
  4. Не хватает опыта (и осознания этого).

Решения (не соответствующие причинам):

  1. Сначала тестирование.
  2. Начать кодирование (+ для удовольствия)
  3. Один выбросить (+ один API выбросить).
  4. Установите временные ограничения.
  5. Сними пух, оставайся с вещами.
  6. Сделайте гибкий код (что-то вроде «выбросить», нет?).

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

Поскольку этот вопрос закрыт, я приму ответ с большинством голосов на сегодняшний день. Когда / если это изменится - я постараюсь следовать.


47
Давление времени очень помогает прекратить обдумывать вещи.
user281377

51

49
Выпейте 2 пива ..
Эндрю Т Финнелл

6
Второй системный эффект, кто-нибудь?
Билли ОНил

21
Ваша проблема не в том, чтобы «знать слишком много», а в том, чтобы анализировать слишком много. Вам не нужно слишком сильно заботиться о производительности, будущих функциях и т. Д., Это не значит, что конец света закончится, если клиент предоставит вам новую функцию, которую немного сложно реализовать
Луис Рис

Ответы:


90

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

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

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

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


15
Официальное название: ЯГНИ .
Марк Рэнсом

48

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

Мой любимый ответ - «Архитектура - это глагол». Перестаньте думать, начните действовать, независимо от того, насколько несовершенно и неэффективно вы и команда будете себя чувствовать. Возможно, первыми действиями могут быть демонтаж неуместной политики.


43

40 лет назад Фред Брукс писал об этом: «Напиши, кого выбросить, ты все равно будешь». Ничего не изменилось........


10
Бывший Джефф Этвуд говорит: «Версия 1 отстой, но все равно отпусти». codinghorror.com/blog/2009/12/…
Алан Б.

5
Это верно для любой версии :)
Неманя Трифунович

2
@AlanB, вот еще один пост с кодирующим ужасом, который застрял в моей памяти.
Бенджол

38

Это неправильно? Это естественная эволюция, или я загнал себя в колею?

По-разному. Это, как правило, общий шаг на пути разработчика.

  1. Начните бросать дерьмо вместе, укусите его в задницу
  2. Начни перерабатывать живой ад из всего, осознай, что ЯГНИ
  3. Устанавливайтесь на некотором прагматичном среднем уровне, где легкие вещи соединяются вместе, а сложным / вероятным изменениям дается достаточно инженерных разработок, чтобы было достаточно легко работать с изменениями.

Это только колея, если вы остаетесь под номером 2.


4
+1 Вы поймете, что находитесь в колее под номером 2, когда начнете перерабатывать «Hello World».
Спойк

3
@Spoike - Или Fizzbuzz. Ала, Предприятие Fizzbuzz !
CraigTP

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

14

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

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

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

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

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

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


Преждевременное обобщение ответственно за большую часть gumph в нашей текущей кодовой базе.
Бенджол

10

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

  1. Определите эпицентр : думайте о своем проекте как о хот-доги, а эпицентром будут хот-доги. Вы можете взять любую другую специю / заправку / овощ со своего стенда и все еще иметь возможность продавать хот-доги. Какова основная цель вашего программного обеспечения? Изолируйте все остальные дополнения и / или добавленную стоимость от них и сосредоточьтесь сначала на эпицентре.
  2. Продолжайте повторять про себя: «делать это позже - значит делать это лучше» : посмотрите, где это имеет смысл, и сделайте небольшую заметку «на потом». Если вы делаете это хорошо и думаете о его реальном использовании, вы получите тот же дизайн, но с приоритетом в дорожной карте.
  3. Diminish-Decouple-Discard : Независимо от того, какой у вас дизайн модуля, вы можете сделать его настолько простым / необходимым / чистым / универсальным, насколько это возможно (иногда это может быть выполнено без удаления функций) Когда вы не можете упростить его дальше, начните отделять элементы, которые могли бы жить сами по себе и иметь цель. В конце концов, если у вас все еще есть жир, вы сможете просто его отрезать.
  4. Отделите «библиотечный код» от «производственного кода» : всегда будет код, который нельзя использовать повторно, но он всегда добавляет шум в дизайн. Этот код содержит бизнес-правила. Вы обнаружите, что иногда некоторые бизнес-правила проще и быстрее изменить ( чрезвычайно важно ), чем с надежной конструкцией. Вы найдете код, на который можно положиться, и код, который клиент должен изменить или переопределить в будущем. Вы хотите, чтобы они были как можно более разрозненными.

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

Я взял 1 и 2 из Rework .


9

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


6
(Не мое отрицательное мнение) Когда вы прекращаете писать тесты? Вы только что поставили проблему за уровень косвенности.
MSalters

2
@MSalters Я думаю, что Грэм имеет в виду TDD, где вы пишете набор тестов перед кодом. Затем вы пишете простейший код, который проходит эти тесты. Тогда вы рефакторинг. Следование этой методике может помешать вам переосмыслить начальную разработку, поскольку ваша цель - выполнить тест, а не создать идеальный код.
Олекси

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

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

2
Тесты помогают определить объем и область применения предмета. Независимо от того, используете ли вы TDD или иным способом, идея определения тестов и их последующей реализации до тех пор, пока эти тесты не будут выполнены, - вот что думает @Graham здесь.
Прит Сангха

4

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


4

При написании и разработке программного обеспечения нужно помнить только о двух вещах: удобство обслуживания и правильность.

Корректность наиболее важна в краткосрочной перспективе и может быть легко подтверждена тестами.

Ремонтопригодность поможет позже в разработке, но ее сложнее определить.

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


3

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


3

Я думаю, что это синдром, что задачи, которые вы делаете, слишком легки для вас.

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

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


3

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

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

2

Это просто паралич анализа. Это случается со многими людьми во многих областях. Вы можете прорваться через это.

Ответ - ПРОСТО ПОЛУЧИТЕ С ЭТОМ ;-)

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

Когда у вас большая программа и ваш мозг работает сверхурочно - сначала просто кодируйте простые случаи. Сначала программа должна быть запущена, затем должна быть введена и т. Д.
Ваша задача состоит в том, чтобы потом было проще обновлять и реорганизовывать код, но код ДОЛЖЕН быть не более сложным, чем это необходимо для выполнения поставленной задачи.

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

Код для следующего задания - ТОЛЬКО. Код просто и хорошо, так что его легко реорганизовать, если вам нужно. Убедитесь, что программа работает. Повторение.


1

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

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

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

Невозможно сделать все правильно, а в некоторых случаях даже ЛЮБОЙ из этого, когда вы начинаете, потому что дизайн - это действительно путешествие открытий; это последнее, а не первое, что нужно сделать.

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

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

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

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

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


0

Вы не слишком много знаете; ты не знаешь достаточно! И вы только недавно поняли это.

Не думайте, что ваш выбор дизайна - это то, что вы должны сделать «правильным», потому что нет «правильного» - есть много «неправильных», но есть и компромиссы (в скорости выполнения, время для завершения кодирования) задача, расширяемость и т. д.). Код, который вы напишите, если он хорошо продуман, все равно будет иметь свои сильные и слабые стороны.

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

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


-1

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


-2

Занимайтесь программированием в свободное время, как вы это делали 10 лет назад, с меньшими заботами и просто весельем.

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


-2

Нет, ты еще недостаточно знаешь.

Пополните свои знания, например, по этим простым правилам:

  • ПОЦЕЛУЙ: Держи это маленьким и простым.
  • ЯГНИ: Тебе это не понадобится.
  • Хуже лучше: некоторые худшие решения на самом деле лучше с точки зрения ремонтопригодности.

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

Итак, сделайте ваш код достаточно гибким, но не более. Вместо этого сделайте себя гибким, купите книгу по рефакторингу.


-2

Две вещи:

  1. Недостаточно много знать. Вы должны иметь мнение о том, что стоит реализовать. Я лично вижу TDD как опору, которая допускает плохую архитектуру. Учитывая огромное количество распространенного мнения, которое работает против меня по этому вопросу, я, вероятно, ошибаюсь, но вопрос о том, внедрять ли TDD в JavaScript, не является проблемой, о которой я думаю, потому что отладка никогда не была большой головной болью для меня, и эй, это будет не первый случай, когда популярное мнение в сообществе разработчиков позже будет расценено как ошибочное. Так что учись быть надменным уколом. По крайней мере, внутри. Вы можете ошибаться, но, по крайней мере, вы делаете то, что работает для вас, а не продумываете вещи, которые не могут.

  2. Похоже, вы начинаете с микро. Начнем с макроса. Сначала инструменты, которые вам нужны, чтобы сделать то, что нужно вашему приложению. Эта часть должна прийти достаточно легко. Тогда начните с проблем архитектуры / интерфейса. То, как соединяется сантехника и с чем она соединяется, должно быть просто хрупкими кусочками поверх всего, что вы можете просто отбросить в сторону и заменить по своей прихоти. Аналогично с деталями того, как все делается. Обернутые правильно они могут быть легко заменены / отредактированы.


-2

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

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

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

Есть много решений для этого, и лучшее, что я видел выше, это установление временного ограничения. Прежде чем начать, решите, сколько времени (1 час?) Вы посвятите анализу и размышлению над этим. Установите таймер.

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

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


-2

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


-3

Ты не безжалостен

http://playswithfire.com/blog/2012/02/19/you-are-not-ruthless-enough/

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.