Динамические языки – хорошо или плохо?

Январь 31, 2009 – 3:03 пп

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

Интерфейс – совокупность средств и методов взаимодействия между элементами системы. В статических компилируемых языках программирования типа C# это выражается в синтаксической конструкции interface, которая позволяет зафиксировать набор методов и свойств реализующих этот интерфейс классов. Сама концепция интерфейса весьма полезна и необходима, так как позволяет абстрагироваться алгоритму от конкретной реализации этого интерфейса, а значит появляется возможность писать более гибкий код, совмещая его со стандартными паттернами программирования. Но посмотрите более внимательно на эту конструкцию и её назначение – интерфейс жестко заставляет реализовать совокупность методов, а ведь это не всегда необходимо. Например, вы реализуете метод, который имеет один формальный параметр и вызывает у него метод ToInt32. Естественно, преследуя цель абстрагирования от реализации, вы создаете интерфейс, который абстрагирует вас от конкретной реализации.

using System;

interface IToInt32
{
	Int32 ToInt32();
}

class MyClass
{
	public static Int32 Processing(IToInt32 obj)
	{
		return obj.ToInt32();
	}
}

Вроде бы все не плохо. Вы создаете классы, реализуете интерфейс IToInt32 и используете метод MyClass.Processing(obj), но вот незадача – вам потребовалось использовать стороннюю библиотеку, классы которой имеют метод ToInt32, но не реализуют интерфейс. Для решения этой проблемы вам потребуется создать адаптер для каждого класса библиотеки и реализовать там интерфейс IToInt32.

class LibClass
{
	public Int32 ToInt32()
	{
		return 0;
	}
}

class AdapterLibClass : LibClass, IToInt32
{
}

Задача решена – классы сторонней библиотеки можно использовать в нашем коде. Но посмотрите каких усилий это потребовало – на каждый класс (!) сторонней библиотеки нам пришлось создать адаптер. А если этих классов тысячи? Объем кода становится уже впечатляющим, а ведь это всего-лишь модельный и упрощенный пример.

Динамические языки предлагают решение этой проблемы – отказ от интерфейсов в классическом понимании. Интерфейсы не упраздняются полностью, но сужаются до одного метода, то есть каждый метод в классе – реализация ещё одного интерфейса. При таком подходе в динамических языках, вроде Python, не требуется создание адаптеров, только конечный код без отвлечения на вспомогательные структуры.

class MyClass :
	@staticmethod
	def Processing(obj) :
		return obj.ToInt32()

class LibClass :
	def ToInt32(self) :
		return 0

if __name__ == '__main__' :
	print( MyClass.Processing( LibClass() ) )

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

За последние полгода работы с Python я вынес несколько правил написания кода с использованием динамических языков программирования:

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

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



Добавить комментарий: