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

Вместо того чтобы писать слишком интеллектуально и туманно, следуйте принципу PIEНарушение принципа PIE может не только снизить читаемость и ясность кода оно также может негативно сказаться на правильности работы. Автор данного кода хотел определить критическую секцию, чтобы в любой момент времени только один поток мог исполнять код в секции (т.е. “действие”). Для этого он пытается блокировать экземпляр класса Cof feeMaker. Поток сможет исполнять данный метод, только если он не заблокирован в данный момент (в Java вместо lock используется synchronized, но смысл тот же).

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

Предположим, наша кофеварка может готовить также просто кипяток для тех, кто утром предпочитает пить чай с бергамотом. Допустим, нам хочется синхронизовать метод GetWater() и мы ставим lock(this) внутри него. Это обеспечит синхронизацию для любого кода, который использует блокировку экземпляра Cof feeMaker с помощью lock. Это приведет к тому, что нельзя готовить кофе и наливать кипяток одновременно. Может, этого мы и добивались, но, вполне вероятно, мы заблокировали больше, чем требуется. Из самого текста кода этого не понять, и его пользователям остается лишь недоумевать.

Кроме того, реализация метода MakeCoffeeO блокирует объект Cof feeMaker, который виден всему приложению. Что произойдет, если вы заблокируете экземпляр Cof feeMaker в одном потоке, а затем другой поток вызовет метод MakeCof fee() для того же объекта? В лучшем случае это снизит производительность, в худшем приведет к взаимной блокировке (deadlock).

Попробуем применить принцип PIE к данному коду, изменив его так, чтобы код стал более определенным. Мы хотим разрешить лишь одному потоку исполнять метод MakeCoffee() в каждый момент времени. Почему бы не создать объект специально для этих целей и не заблокировать его?

private object makeCoffeeLock = new object(): public void MakeCoffee()
(
lock(makeCoffeeLock)
(
// . действие
)
)

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

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

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

На что это похоже

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

Сохраняйте равновесие

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

Для вас не существует приятия потом. Если вы не сделаете этого прямо сейчас, вы не сможете сделать это потом.

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

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

tel-icq