Відповідність функцій принципу єдиної відповідальності

Якщо вивчати класиків, а саме Роберта Мартіна, то він сам плутається у тому, що таке принцип єдиної відповідальності (SRP – Single Responsibility Principle), тому я просто вкраду стару назву і вкладу у неї новий сенс. У цій публікації я торкнусь лише функцій, проте я вважаю функції основною будівельною одиницею і дуже доброю абстракцією в умовно вищих та нижчих пластах.

Феномени та слова

Принцип єдиної відповідальності, якщо, розглядати з точки зору філософії лінгвістики, виглядає тісно пов’язаним з поняттям феномену. Що таке феномен? Є декілька пояснень, але я буду користуватися наступним:

Феномен – це те, що пізнається через відчуття. Феномен – це не лише матеріальний об’єкт, а й будь-яка його властивість, його дія, відчуття чи стан. У реченні “Курча було жовтим, а потім виросло у білого півника.”, слова “курча”, “(було) жовтим”, “виросло”, “білого”, “півника” називають феномени, оскільки курча та його колір можна побачити, а також можна побачити розвиток курча у півня та зміну кольору на білий.

Для кожного феномену використовується одиночне слово. Тобто, декілька одиночних слів можуть називати один феномен, але словосплолучення не називає одного феномену. Наприклад, “курча жовте” це не один феномен, а декілька: “існує курча”, “існують кольори”, “один з кольорів – жовтий”, “курча має колір”, “колір який має курча – жовтий”. 

Принцип єдиної відповідальності

Повертаємось до принципу єдиної відповідальності. Його можна інакше сформулювати наступною еврістикою(???): функція повинна мати назву із одного слова. Навіть якщо функція виконує декілька дій, то вона має називатися єдиним словом, адже поєднує сукупність дій у щось єдине.

Наприклад, сукупність складних, спеціально організованих  рухів, які спрямовані на виклик естетичного почуття у глядача та/або почуття задоволення у виконавців називаються танком. Для феномену цього складного процессу існує всього лише одиноке слово “танок”. Якщо виникає бажання назвати функцію декількома словами, то вона, або має належати більш вузькому контексту/простору імен, або вона має погану гранулярність, тобто бере на себе більше, ніж має брати одна функція. Це така проста еврістика, яка допомогає краще фрагментувати та організовувати код.

Принцип єдиної відповідальності пов’язаний саме з гранулярністю, тобто тим, як ми визначаємо феномени і як ми приєднуємо до феноменів те, що їм не належить.

Якщо ми розглянемо оператор ділення “/” у Golang, то помітимо, що він приймає два числа та повертає одне число, або “викликає паніку” якщо ми намагаємося ділити на нуль.

package main

import (
	"fmt"
	"log"
)

func div(x, y int) int {
	return x / y
}
func main() {
	defer func() {
		if err := recover(); err != nil {
			log.Println("panic:", err)
		}
	}()

	fmt.Printf("\n1 / 0 = %f\n", div(1, 0))
}

The Go playground

Отже, оператор ділення виконує три дії: (1) перевірку аргументів, (2) паніку або (3) власне ділення, якщо y != nil. Досвідчені розробники знайомі з цим, адже ділення для них – це дуже відома операція, а от новачку це не очевидно, оскільки в арифметиці, яку він вчив у школі ніяких перевірок та помилок у операції ділення не було. Просто не можна було ділити на нуль. Якщо взяти до уваги якісь менш популярні функції, то вже й досвідченому розробнику не завжди відомо, що саме вони виконують, та які ефекти можуть породжувати. Це дуже погано, оскільки ми отримуємо код, що компілюється, але не працює.

Висновок

Я впевнений, що сигнатури функцій мають надавати максимально повну інформацію щодо обмежень діапазонів вхідних значень на яких функція об’явлена. Завдяки цьому система типів позбавить нас необхідності писати значну частину коду для перевірок значень, що були передані до функцій та від породження локальних для функцій неявних підтипів та помилок з ними пов’язаних.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *