<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Денис Королёв</title><author><name>Денис Королёв</name></author><id>https://teletype.in/atom/leprosus</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/leprosus?offset=0"></link><link rel="alternate" type="text/html" href="https://leprosus.ru/?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=leprosus"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/leprosus?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-05-05T10:45:17.061Z</updated><entry><id>leprosus:feasibility-study-methodology</id><link rel="alternate" type="text/html" href="https://leprosus.ru/feasibility-study-methodology?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=leprosus"></link><title>Технико-экономическое обоснование (ТЭО) в жизни инженера</title><published>2025-07-05T20:46:21.371Z</published><updated>2025-07-12T14:27:10.830Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/f4/c9/f4c9b00e-c593-46c2-b724-cfe23a00d3d8.png"></media:thumbnail><category term="metodologii" label="Методологии"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/c0/9b/c09b9848-782e-4147-ad18-2071ad4c2568.jpeg&quot;&gt;Данную статью я бы начал с простого ответа на вопрос читателя: &quot;на кой мне про это знать?&quot;</summary><content type="html">
  &lt;p id=&quot;wsKb&quot;&gt;Данную статью я бы начал с простого ответа на вопрос читателя: &amp;quot;на кой мне про это знать?&amp;quot;&lt;/p&gt;
  &lt;p id=&quot;qiQw&quot;&gt;Любой инженер во время работы сталкивается с ситуацией, требующей от него принять решение в пользу той или иной технологии, методики, способа.&lt;/p&gt;
  &lt;figure id=&quot;CdTy&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c0/9b/c09b9848-782e-4147-ad18-2071ad4c2568.jpeg&quot; width=&quot;1280&quot; /&gt;
    &lt;figcaption&gt;Let&amp;#x27;s help crypto housekeeper Kuza make the right choice.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;nbqL&quot;&gt;Современный инженер, я сужу исходя из собственной насмотренности, использует интуицию в качестве одного из сильнейших своих &amp;quot;профессиональных навыков&amp;quot;.&lt;/p&gt;
  &lt;p id=&quot;Hu1t&quot;&gt;В статье речь пойдёт именно про подход как осознанно и объективно принять выбор.&lt;/p&gt;
  &lt;h2 id=&quot;zT4t&quot;&gt;Задача&lt;/h2&gt;
  &lt;p id=&quot;qv9f&quot;&gt;В качестве задачи предлагаю сделать выбор быстрого алгоритма шифрования для обеспечения целостности данных за счёт цифровой подписи с минимальной утилизацией ресурсов для языка программирования &lt;a href=&quot;https://go.dev/&quot; target=&quot;_blank&quot;&gt;golang&lt;/a&gt;&lt;/p&gt;
  &lt;h2 id=&quot;mRwV&quot;&gt;Возможные варианты&lt;/h2&gt;
  &lt;p id=&quot;SEDg&quot;&gt;На рынке существует несколько решений, от всем известных, до государством одобряемых.&lt;/p&gt;
  &lt;p id=&quot;1cK5&quot;&gt;Перечислим их:&lt;/p&gt;
  &lt;ul id=&quot;pZpd&quot;&gt;
    &lt;li id=&quot;EvWi&quot;&gt;&lt;a href=&quot;https://pkg.go.dev/crypto/rsa&quot; target=&quot;_blank&quot;&gt;RSA&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;dYq1&quot;&gt;&lt;a href=&quot;https://pkg.go.dev/crypto/ed25519&quot; target=&quot;_blank&quot;&gt;Ed25519&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;WmlP&quot;&gt;&lt;a href=&quot;https://github.com/ddulesov/gogost&quot; target=&quot;_blank&quot;&gt;ГОСТ Р 34.10&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;sqID&quot;&gt;Критерии оценки&lt;/h2&gt;
  &lt;p id=&quot;7OpR&quot;&gt;Методика называется технико-экономическое обоснование не спроста.&lt;/p&gt;
  &lt;p id=&quot;MHDw&quot;&gt;Это означает, что нужно придумать список технических и экономических критериев для оценки.&lt;/p&gt;
  &lt;h3 id=&quot;y5jH&quot;&gt;Технические критерии&lt;/h3&gt;
  &lt;pre id=&quot;sGn6&quot; data-lang=&quot;markdown&quot;&gt;| Наименование         | Вес | Обоснование веса                                                            |
|----------------------|-----|-----------------------------------------------------------------------------|
| Утилизация CPU       | 3   | Самая дорогая стоимость масштабирования                                     |
| Утилизация RAM       | 2   | Средняя стоимость масштабирования                                           |
| Наличие зависимостей | 2   | Чем больше зависимостей, тем выше вероятность внешнего дефекта и уязвимости |&lt;/pre&gt;
  &lt;p id=&quot;QjV2&quot;&gt;&lt;strong&gt;Почему вес утилизации CPU - 3?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;sxss&quot;&gt;Это обусловлено стоимостью увеличения производительности CPU, на текущий момент она самая высокая.&lt;/p&gt;
  &lt;p id=&quot;zICy&quot;&gt;&lt;strong&gt;Почему вес утилизации RAM - 2?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;p6qy&quot;&gt;Стоимость расширения же RAM уступает по цене улучшению CPU; масштабирование всё ещё не бесплатно.&lt;/p&gt;
  &lt;p id=&quot;eEqs&quot;&gt;&lt;strong&gt;Почему наличие зависимостей - плохо?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;3m7H&quot;&gt;Говоря языком математики (теорией вероятностей), то любое стороннее решение - это некая вероятность дефекта &lt;em&gt;&lt;u&gt;P(defect)&lt;/u&gt;&lt;/em&gt;, допущенного сторонним разработчиком, плюс вероятность уязвимости &lt;u&gt;&lt;em&gt;P(vulnerability)&lt;/em&gt;&lt;/u&gt;.&lt;/p&gt;
  &lt;p id=&quot;fzkD&quot;&gt;Грубо говоря, каждая прямая зависимость обладает вероятностью, что вам, как инженеру, принявшему решение использовать ту или иную зависимость, придётся нести ответственность за внешнего разработчика:&lt;/p&gt;
  &lt;pre id=&quot;t6Dp&quot; data-lang=&quot;latex&quot;&gt;P(dependency) = P(defect) + P(vulnerability)&lt;/pre&gt;
  &lt;p id=&quot;vQSV&quot;&gt;Если зависимостей несколько, то вероятностью является сумма каждой зависимости:&lt;/p&gt;
  &lt;pre id=&quot;XopB&quot; data-lang=&quot;latex&quot;&gt;P(dependency) = P(dependency 1) + P(dependency 2) + ... + P(dependency N)&lt;/pre&gt;
  &lt;p id=&quot;S0Df&quot;&gt;Как оценить эти вероятности - это отдельная большая статья (пишите в комментарии, интересно ли будет про такое читать).&lt;/p&gt;
  &lt;h3 id=&quot;HpFm&quot;&gt;Экономические критерии&lt;/h3&gt;
  &lt;pre id=&quot;1StE&quot; data-lang=&quot;markdown&quot;&gt;| Наименование            | Вес | Обоснование веса                          |
|-------------------------|-----|-------------------------------------------|
| Стоимость владения      | 2   | Для сокрашения статических затрат         |
| Стоимость сопровождения | 3   | Для сокрашения динамических затрат        |
| Стоимость внедрения     | 1   | Каждое решение обладает разной сложностью |&lt;/pre&gt;
  &lt;p id=&quot;5QOM&quot;&gt;&lt;strong&gt;Почему вес стоимости владения - 2?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;ISuQ&quot;&gt;Сперва определим, что это такое: это та стоимость, которую нужно выплатить за использование. В нашем списке речь идёт про открытые алгоритмы шифрования, стоимость которых пока равна нулю.&lt;/p&gt;
  &lt;p id=&quot;5XMz&quot;&gt;Отвечая на вопрос, если даже стоимость владения была бы выше нуля, то для любой коммерческой компании эта затрата была бы разовой (для пожизненной лицензии) или ежегодной (для подписной модели).&lt;/p&gt;
  &lt;p id=&quot;bS53&quot;&gt;&lt;strong&gt;Почему вес стоимости сопровождения - 3?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;TOaQ&quot;&gt;Стоимость зарплат инженеров по эксплуатации и разработке чаще всего заметно выше лицензионных сборов, поэтому вес выше предыдущего.&lt;/p&gt;
  &lt;p id=&quot;9jr3&quot;&gt;&lt;strong&gt;Почему вес стоимости внедрения - 1?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;wVcR&quot;&gt;Разработка ПО для компании на базе любого из перечисленных решений будет стоить какого-то количества человеко-часов, которые никогда не бывают бесплатными.&lt;/p&gt;
  &lt;h2 id=&quot;aEZR&quot;&gt;Эксперимент&lt;/h2&gt;
  &lt;h3 id=&quot;ODEN&quot;&gt;Что будет выполнять&lt;/h3&gt;
  &lt;p id=&quot;65wP&quot;&gt;Алгоритм должен взять тестовый набор данных, сгенерировать для него подпись и её проверить для указанных данных.&lt;/p&gt;
  &lt;h3 id=&quot;CRvp&quot;&gt;Детали&lt;/h3&gt;
  &lt;p id=&quot;oZwp&quot;&gt;Для проведения эксперимента будут использоваться базовые инструменты языка программирования. &lt;/p&gt;
  &lt;p id=&quot;gBfI&quot;&gt;Также будут добавлены следующие флаги для запуска тестов:&lt;/p&gt;
  &lt;ul id=&quot;3oIn&quot;&gt;
    &lt;li id=&quot;ByZ2&quot;&gt;test.benchmem - для отображения утилизации RAM&lt;/li&gt;
    &lt;li id=&quot;ia9G&quot;&gt;test.benchtime=5s - для увеличения эксперимента с 1 секунды до 5&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;tFu7&quot;&gt;Эксперимент будет проводиться на железе:&lt;/p&gt;
  &lt;ul id=&quot;jC3q&quot;&gt;
    &lt;li id=&quot;rfxm&quot;&gt;ОС - MacOS&lt;/li&gt;
    &lt;li id=&quot;MgyC&quot;&gt;CPU - Apple M3 Max (ARM64)&lt;/li&gt;
    &lt;li id=&quot;HMpF&quot;&gt;RAM - 48 Gb&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;W026&quot;&gt;Benchmark для RSA с 2048 битным ключём&lt;/h3&gt;
  &lt;p id=&quot;DhoQ&quot;&gt;&lt;strong&gt;Почему 2048 битный ключ?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;cwGx&quot;&gt;Алгоритм шифрования RSA достаточно старый, обладает определённым набором криптографических слабостей. Для того, чтобы его справедливо уравнять с остальными, ключ шифрования необходимо увеличить. Чтобы сравнение было хоть сколько-то адекватно, увеличивать ключ до бесконечности мы не можем. На текущий момент двухкилобитный ключ вполне достаточен.&lt;/p&gt;
  &lt;blockquote id=&quot;EtSQ&quot;&gt;Конечно, для принятия более взвешенного решения, нужно бы отдельно провести анализ размера ключа, для обеспечения более объективного выбора. Я отказался от этого в пользу сохранения читаемости текста.&lt;/blockquote&gt;
  &lt;pre id=&quot;HehN&quot; data-lang=&quot;go&quot;&gt;package test

import (
	&amp;quot;crypto&amp;quot;
	&amp;quot;crypto/rand&amp;quot;
	&amp;quot;crypto/rsa&amp;quot;
	&amp;quot;log&amp;quot;
	&amp;quot;testing&amp;quot;
)

var msg = []byte(&amp;quot;Let&amp;#x27;s help crypto housekeeper Kuza make the right choice&amp;quot;)

func BenchmarkRSA2048(b *testing.B) {
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		log.Fatal(err)
	}

	pub := &amp;amp;priv.PublicKey

	var sign []byte

	b.ResetTimer()
	for i := 0; i &amp;lt; b.N; i++ {
		sign, err = rsa.SignPKCS1v15(rand.Reader, priv, crypto.Hash(0), msg)
		if err != nil {
			log.Fatal(err)
		}

		err = rsa.VerifyPKCS1v15(pub, crypto.Hash(0), msg, sign)
		if err != nil {
			log.Fatal(err)
		}
	}
}&lt;/pre&gt;
  &lt;p id=&quot;YM8I&quot;&gt;Что важно отметить:&lt;/p&gt;
  &lt;ul id=&quot;J80g&quot;&gt;
    &lt;li id=&quot;7MFR&quot;&gt;код максимально простой&lt;/li&gt;
    &lt;li id=&quot;RF7v&quot;&gt;данный алгоритм входит в базовые зависимости языка программирования&lt;/li&gt;
    &lt;li id=&quot;XXrX&quot;&gt;данные не хешируются для создания подписи и её верификации&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;z2sT&quot;&gt;Результат:&lt;/p&gt;
  &lt;pre id=&quot;j4pn&quot; data-lang=&quot;shell&quot;&gt;goos: darwin
goarch: arm64
cpu: Apple M3 Max
BenchmarkRSA2048-10    1,308    923,656 ns/op&lt;/pre&gt;
  &lt;h3 id=&quot;ID32&quot;&gt;Benchmark для Ed25519&lt;/h3&gt;
  &lt;pre id=&quot;WExq&quot; data-lang=&quot;go&quot;&gt;package test

import (
	&amp;quot;crypto&amp;quot;
	&amp;quot;crypto/ed25519&amp;quot;
	&amp;quot;log&amp;quot;
	&amp;quot;testing&amp;quot;
)

var msg = []byte(&amp;quot;Let&amp;#x27;s help crypto housekeeper Kuza make the right choice&amp;quot;)

func BenchmarkEd25519(b *testing.B) {
	pub, priv, err := ed25519.GenerateKey(nil)
	if err != nil {
		log.Fatal(err)
	}

	var sign []byte

	b.ResetTimer()
	for i := 0; i &amp;lt; b.N; i++ {
		sign, err = priv.Sign(nil, msg, &amp;amp;ed25519.Options{})
		if err != nil {
			log.Fatal(err)
		}

		err = ed25519.VerifyWithOptions(pub, msg, sign, &amp;amp;ed25519.Options{})
		if err != nil {
			log.Fatal(err)
		}
	}
}
&lt;/pre&gt;
  &lt;p id=&quot;BQeB&quot;&gt;Что важно отметить:&lt;/p&gt;
  &lt;ul id=&quot;AvNS&quot;&gt;
    &lt;li id=&quot;6Dp2&quot;&gt;код максимально простой&lt;/li&gt;
    &lt;li id=&quot;sNDf&quot;&gt;данный алгоритм входит в базовые зависимости языка программирования&lt;/li&gt;
    &lt;li id=&quot;47iy&quot;&gt;данные не хешируются для создания подписи и её верификации&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;ieJv&quot;&gt;Результат:&lt;/p&gt;
  &lt;pre id=&quot;L18j&quot; data-lang=&quot;shell&quot;&gt;goos: darwin
goarch: arm64
cpu: Apple M3 Max
BenchmarkEd25519-10    15,927    73,565 ns/op&lt;/pre&gt;
  &lt;h3 id=&quot;7bfb&quot;&gt;Benchmark для ГОСТ Р 34.10&lt;/h3&gt;
  &lt;pre id=&quot;tabw&quot; data-lang=&quot;go&quot;&gt;package test

import (
	&amp;quot;crypto&amp;quot;
	&amp;quot;crypto/rand&amp;quot;
	&amp;quot;log&amp;quot;
	&amp;quot;testing&amp;quot;

	&amp;quot;github.com/ddulesov/gogost/gost3410&amp;quot;
)

var msg = []byte(&amp;quot;Let&amp;#x27;s help crypto housekeeper Kuza make the right choice&amp;quot;)

func BenchmarkGOST3410(b *testing.B) {
	curve := gost3410.CurveIdtc26gost341012512paramSetA()

	priv, err := gost3410.GenPrivateKey(curve, gost3410.Mode2012, rand.Reader)
	if err != nil {
		b.Fatal(err)
	}

	var pub *gost3410.PublicKey

	pub, err = priv.PublicKey()
	if err != nil {
		b.Fatal(err)
	}

	var sign []byte

	b.ResetTimer()
	for i := 0; i &amp;lt; b.N; i++ {
		sign, err = priv.SignDigest(msg, rand.Reader)
		if err != nil {
			b.Fatal(err)
		}

		_, err = pub.VerifyDigest(msg, sign)
		if err != nil {
			b.Fatal(err)
		}
	}
}&lt;/pre&gt;
  &lt;p id=&quot;fmKt&quot;&gt;Что важно отметить:&lt;/p&gt;
  &lt;ul id=&quot;RTvv&quot;&gt;
    &lt;li id=&quot;nPsg&quot;&gt;в государственных структурах до сих пор не научились давать адекватные названия&lt;/li&gt;
    &lt;li id=&quot;wEtk&quot;&gt;сигнатура зависимости местами далека от интуитивно понятной&lt;/li&gt;
    &lt;li id=&quot;D2zh&quot;&gt;данный алгоритм является внешним, поставляется отдельной зависимостью&lt;/li&gt;
    &lt;li id=&quot;5MeU&quot;&gt;данные не хешируются для создания подписи и её верификации&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;iH6w&quot;&gt;Результат:&lt;/p&gt;
  &lt;pre id=&quot;oWds&quot; data-lang=&quot;shell&quot;&gt;goos: darwin
goarch: arm64
cpu: Apple M3 Max
BenchmarkGOST3410-10    80    12,692,735 ns/op&lt;/pre&gt;
  &lt;h3 id=&quot;4466&quot;&gt;Сводная таблица результатов&lt;/h3&gt;
  &lt;pre id=&quot;8XTh&quot;&gt;| Эксперимент | Время | Итераций | Время одной операции | Утилизация RAM | Аллокаций RAM |
|-------------|-------|----------|----------------------|----------------|---------------|
| RSA2048     | 5 s   | 6415     | 900,552 ns           | 1,888          | 11            |
| Ed25519     | 5 s   | 81256    | 74,015 ns            | 88             | 2             |
| GOST3410    | 5 s   | 471      | 12,407,072 ns        | 3,981,786      | 48,399        |&lt;/pre&gt;
  &lt;p id=&quot;H3do&quot;&gt;Пояснения:&lt;/p&gt;
  &lt;ul id=&quot;Hmbb&quot;&gt;
    &lt;li id=&quot;alOo&quot;&gt;Время - это период прохождения эксперимент&lt;/li&gt;
    &lt;li id=&quot;epQQ&quot;&gt;Итераций - число успешных операций подписи и её проверки&lt;/li&gt;
    &lt;li id=&quot;6uCf&quot;&gt;Время одной операции - это необходимый период, требуемый железу на выполнение одного цикла генерации подписи и её проверки&lt;/li&gt;
    &lt;li id=&quot;gIVt&quot;&gt;Утилизация RAM - сколько байт памяти будет выделено для выполнения одного цикла&lt;/li&gt;
    &lt;li id=&quot;V9rX&quot;&gt;Аллокаций RAM - сколько выделений памяти будет сделано для выполнения одного цикла&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;ISIQ&quot;&gt;Интерпретация результатов&lt;/h3&gt;
  &lt;pre id=&quot;WITu&quot;&gt;| Оценка                             | Вес | RSA2048 | Ed25519 | GOST3410 |
|------------------------------------|-----|---------|---------|----------|
| Утилизация CPU                     | 3   | M       | S       | L        |
| Утилизация RAM                     | 2   | M       | S       | L        |
| Наличие зависимостей у решения     | 2   | -       | -       | +        |
| Стоимость владения технологией     | 2   | 0       | 0       | 0        |
| Стоимость сопровождения технологии | 3   | S       | S       | S        |
| Стоимость внедрения                | 1   | S       | S       | S        |&lt;/pre&gt;
  &lt;p id=&quot;ekG8&quot;&gt;Легенда:&lt;/p&gt;
  &lt;ul id=&quot;a2Qc&quot;&gt;
    &lt;li id=&quot;Bvri&quot;&gt;&lt;strong&gt;L&lt;/strong&gt; - высокая (значение - 3)&lt;/li&gt;
    &lt;li id=&quot;Dqji&quot;&gt;&lt;strong&gt;M&lt;/strong&gt; - средняя (значение - 2)&lt;/li&gt;
    &lt;li id=&quot;znPY&quot;&gt;&lt;strong&gt;S&lt;/strong&gt; - низкая (значение - 1)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;VLtQ&quot;&gt;Пояснения:&lt;/p&gt;
  &lt;ul id=&quot;3uCd&quot;&gt;
    &lt;li id=&quot;SMPb&quot;&gt;Самая высокая утилизация CPU у ГОСТ Р 34.10, времени на одну операцию требуется разительно больше, чем остальным; на втором месте идёт RSA; лидером является - Ed25519&lt;/li&gt;
    &lt;li id=&quot;tOUW&quot;&gt;Самая высокая утилизация RAM и высокое число аллокаций также у ГОСТ Р 34.10; на втором месте - RSA; лидером является - Ed25519&lt;/li&gt;
    &lt;li id=&quot;zKGI&quot;&gt;ГОСТ Р 34.10 выполнено отдельной зависимостью, остальные решения поддерживаются языком программирования&lt;/li&gt;
    &lt;li id=&quot;OFoi&quot;&gt;Для использования всех трёх алгоритмов не потребуется никаких выплат - все они поставляются под свободными лицензиями&lt;/li&gt;
    &lt;li id=&quot;k8kw&quot;&gt;Как показали примеры кода выше, реализация нужного алгоритма на базе каждого из решений не потребует больших интеллектуальных вложений, следовательно, стоимости сопровождения и внедрения будут низкими&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;x9ou&quot;&gt;Расчёты&lt;/h3&gt;
  &lt;p id=&quot;1yuN&quot;&gt;Для того, чтобы мы могли сравнить алгоритмы, нужно написать формулу для расчёта оценок.&lt;/p&gt;
  &lt;p id=&quot;QHqf&quot;&gt;Предлагаю использовать вот такую достаточно простую для понимания формулу:&lt;/p&gt;
  &lt;pre id=&quot;GTw1&quot; data-lang=&quot;latex&quot;&gt;score = сpu_util * cpu_util_weight 
      + ram_util * ram_util_weight
      + is_dep * is_dep_weight
      + stat_cost * stat_cost_weight
      + dyn_cost * stat_cost_weight
      + integ_cost * integ_cost_weight&lt;/pre&gt;
  &lt;p id=&quot;oFGI&quot;&gt;Что есть что:&lt;/p&gt;
  &lt;ul id=&quot;dxuY&quot;&gt;
    &lt;li id=&quot;FMAP&quot;&gt;сpu_util - утилизация CPU&lt;/li&gt;
    &lt;li id=&quot;XWz3&quot;&gt;ram_util - утилизация RAM&lt;/li&gt;
    &lt;li id=&quot;Ptud&quot;&gt;is_dep - поставляется отдельной зависимостью или нет&lt;/li&gt;
    &lt;li id=&quot;2OY0&quot;&gt;stat_cost - величина статической стоимости&lt;/li&gt;
    &lt;li id=&quot;dlcX&quot;&gt;dyn_cost - величина динамической стоимости&lt;/li&gt;
    &lt;li id=&quot;14rb&quot;&gt;integ_cost - величина стоимости внедрения&lt;/li&gt;
    &lt;li id=&quot;8Z9b&quot;&gt;_weight - это веса из таблиц с &lt;a href=&quot;#sqID&quot;&gt;критериями оценки&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;mwXz&quot; data-lang=&quot;latex&quot;&gt;rsa_score = 2*3 + 2*2 + 0*2 + 0*2 + 1*3 + 1*1 = 14

ed25519_score = 1*3 + 1*2 + 0*2 + 0*2 + 1*3 + 1*1 = 9

gost3410_score = 3*3 + 3*2 + 1*2 + 0*2 + 1*3 + 1*1 = 21&lt;/pre&gt;
  &lt;h2 id=&quot;wzwx&quot;&gt;Выводы&lt;/h2&gt;
  &lt;p id=&quot;AMyU&quot;&gt;Лучшее решение обладает меньшей оценкой. Из приведённых расчётов к такому относятся &lt;strong&gt;Ed25519&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;Snlq&quot;&gt;&lt;strong&gt;ГОСТ Р 34.10&lt;/strong&gt;, сравнивая со всеми остальными решениями, обладает наибольшей утилизацией, как CPU, так и RAM.&lt;br /&gt;Стоимость использования такого решения будет оставаться высокой.&lt;/p&gt;
  &lt;p id=&quot;4ohF&quot;&gt;&lt;strong&gt;RSA c 2048 битным ключом&lt;/strong&gt; утилизирует аппаратные ресурсы заметно слабее, но на порядок выше, чем это делает &lt;strong&gt;Ed25519&lt;/strong&gt;.&lt;/p&gt;
  &lt;h2 id=&quot;j6JZ&quot;&gt;PS&lt;/h2&gt;
  &lt;p id=&quot;q2lq&quot;&gt;Прочитав эту статью, надеюсь, вы начнёте чаще использовать объективный выбор и его же требовать от руководителей, что должно сократить число богемы в мире ИТ 😎&lt;/p&gt;

</content></entry><entry><id>leprosus:kiss-principle</id><link rel="alternate" type="text/html" href="https://leprosus.ru/kiss-principle?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=leprosus"></link><title>Принцип KISS - Keep It Simple, Stupid</title><published>2024-11-20T15:09:57.217Z</published><updated>2024-11-21T09:17:02.813Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/f4/6d/f46d1d66-e412-4bd5-9cc3-a8e47e2ad145.png"></media:thumbnail><category term="principy" label="Принципы"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/f9/0a/f90a86a9-47f8-4675-a1cb-1a4736d44444.png&quot;&gt;Принцип KISS был разработан ВМС США в 1960 году.</summary><content type="html">
  &lt;p id=&quot;skUd&quot;&gt;Принцип &lt;strong&gt;KISS&lt;/strong&gt; был разработан ВМС США в 1960 году.&lt;/p&gt;
  &lt;p id=&quot;qjbs&quot;&gt;Он гласит: простые системы будут работать лучше и надежнее.&lt;/p&gt;
  &lt;figure id=&quot;TKtE&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f9/0a/f90a86a9-47f8-4675-a1cb-1a4736d44444.png&quot; width=&quot;1344&quot; /&gt;
    &lt;figcaption&gt;Американские первооткрыватели реликта KISS&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;S8DM&quot;&gt;Применительно к разработке ПО принцип означает: не придумывай к задаче более сложного решения, чем ей требуется.&lt;/p&gt;
  &lt;p id=&quot;4GIt&quot;&gt;Во время разработки сложного проекта часто приходится сталкиваться с избыточно сложной реализацией. Наш мозг плохо справляются с нахождением решения для комплексной задачи. Чтобы уменьшить сложности, необходимо разделить задачу на мелкие простые задачи и решать их последовательно.&lt;/p&gt;
  &lt;p id=&quot;jQ7J&quot;&gt;Перефразирую социального психолога &lt;strong&gt;Гюстова Лебона&lt;/strong&gt;:&lt;/p&gt;
  &lt;blockquote id=&quot;U1nd&quot;&gt;Мамонта нужно есть по кусочкам&lt;/blockquote&gt;
  &lt;h2 id=&quot;BD16&quot;&gt;Пример&lt;/h2&gt;
  &lt;p id=&quot;tAZX&quot;&gt;У большинства серверного ПО есть пользовательская авторизация. Это некий компонент, отвечающий за управление доступами пользователей. Он может взаимодействовать с другими компонентами системы, чтобы разрешать или запрещать ту или иную функциональность для конкретного пользователя.&lt;/p&gt;
  &lt;p id=&quot;bnxJ&quot;&gt;Разделяя систему на простые компоненты, можно реализовать систему, которая будет состоять из простых и неделимых, отвечающих за определенные действия. Такие компоненты можно организовать в отдельные небольшие блоки кода, каждый из которых будет решать только узкую задачу.&lt;/p&gt;
  &lt;blockquote id=&quot;fgDb&quot;&gt;Для решения декомпозиции комплексной задачи следует использовать принцип &lt;a href=&quot;https://ru.wikipedia.org/wiki/Проблемно-ориентированное_проектирование&quot; target=&quot;_blank&quot;&gt;DDD(Domain-driven design)&lt;/a&gt;.&lt;/blockquote&gt;
  &lt;h2 id=&quot;uCjS&quot;&gt;Причина появления&lt;/h2&gt;
  &lt;ul id=&quot;jFTV&quot;&gt;
    &lt;li id=&quot;1fZm&quot;&gt;Низкая квалификация разработчика&lt;/li&gt;
    &lt;li id=&quot;D0NH&quot;&gt;Когда обучение происходит на базе онлайн-курсов, а не фундаментальных знаний/книг&lt;/li&gt;
    &lt;li id=&quot;dcBt&quot;&gt;Когда нет системного мышления&lt;/li&gt;
    &lt;li id=&quot;zhaA&quot;&gt;Когда сроки реализации функциональности сокращены доне́льзя&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;XTf0&quot;&gt;Почему сложные решения - это плохо&lt;/h2&gt;
  &lt;ol id=&quot;t701&quot;&gt;
    &lt;li id=&quot;lfO8&quot;&gt;&lt;strong&gt;Сложность сопровождения&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;TEvT&quot;&gt;
      &lt;li id=&quot;dKMF&quot;&gt;Нужно затрачивать ощутимо больше времени на перечитывание сложного кода&lt;/li&gt;
      &lt;li id=&quot;iHfC&quot;&gt;Страх у другого разработчика менять код, который он не понимает или понимает плохо&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;PYlb&quot;&gt;&lt;strong&gt;Стоимость разработки/сопровождения&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;3kv0&quot;&gt;
      &lt;li id=&quot;lHl2&quot;&gt;Нужно потратить ощутимо больше времени для понимания и потом для изменения кода, а время разработчика стоит дорого&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;bc5z&quot;&gt;&lt;strong&gt;Когнитивное усложнение кода&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;C1nE&quot;&gt;
      &lt;li id=&quot;IW49&quot;&gt;Так уж устроен наш мозг, что после когнитивно сложной задачи ему нужно немного отдохнуть. В течение времени, который мозг выделил себе на отдых, а это делает именно мозг, а не воля его владельца, его владелец не сможет эффективно переключить его работу на новую задачу, как следствие, владелец начинает прокрастинировать.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;ZYny&quot;&gt;Как обнаружить проблему&lt;/h2&gt;
  &lt;ul id=&quot;zKJv&quot;&gt;
    &lt;li id=&quot;YSXB&quot;&gt;Если для понимания кодовой базы не достаточно бегло пробежать глазами по нему, требуется перечитывать или доставать старый ойуунский бубен и стучать в него;&lt;/li&gt;
    &lt;li id=&quot;XKpS&quot;&gt;Если функция/метод содержит больше 50 строк (тут важна не сама цифра, а понимание порядка);&lt;/li&gt;
    &lt;li id=&quot;eN1N&quot;&gt;Если функция/метод состоит из 5 аргументов (тут тоже цифра может изменяться в зависимости от ЯП, для низкоуровневых языков и 3 аргумента может оказаться сложным)&lt;/li&gt;
    &lt;li id=&quot;u1hC&quot;&gt;Если код необходимо пояснять комментариями&lt;/li&gt;
    &lt;li id=&quot;ec9E&quot;&gt;Когда требуется открыть большое количество скриптов, чтобы понять реализованную функциональность&lt;/li&gt;
    &lt;li id=&quot;wuXA&quot;&gt;Когда сопровождение и/или развитие кодовой базы требует значительного вложения человеко-часов&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;SLgr&quot;&gt;Как исправить проблему&lt;/h2&gt;
  &lt;ul id=&quot;Uu9K&quot;&gt;
    &lt;li id=&quot;Y00R&quot;&gt;Разбить код на небольшие короткие блоки, которые выполняют простые атомарные действия&lt;/li&gt;
    &lt;li id=&quot;JChu&quot;&gt;Сложный код разбить на группу простых функций/методов&lt;/li&gt;
    &lt;li id=&quot;Cdwv&quot;&gt;Провести рефакторинг наименования, дать говорящие названия (функции/методы должны говорить, что они делают и в каком контексте, например: getUserByEmail вместо userEmail, переменные должны иметь понятные читаемы названия и не требовать комментариев, например: sortedUsersByLastVisit вместо users)&lt;/li&gt;
    &lt;li id=&quot;X5dh&quot;&gt;Воспользоваться статичтическими анализатора кода с максимально чувствительными настройками и исправить код по его рекомендациям&lt;/li&gt;
    &lt;li id=&quot;LyYD&quot;&gt;Просканировать кодовую массу анализаторами, которые рассчитывают &lt;a href=&quot;https://en.wikipedia.org/wiki/Cyclomatic_complexity&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;cyclomatic complexity&lt;/strong&gt;&lt;/a&gt; и &lt;a href=&quot;https://en.wikipedia.org/wiki/Cognitive_complexity&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;cognitive complexity&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;6u9M&quot;&gt;Запросить &lt;strong&gt;code review&lt;/strong&gt; у коллег или друзей, чтобы получить альтернативное мнение о коде&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;rzB8&quot;&gt;Подходов и решений для профилактики данной проблемы много, главное помнить о необходимости придерживаться данного принципа.&lt;/p&gt;

</content></entry><entry><id>leprosus:user-story-methodology</id><link rel="alternate" type="text/html" href="https://leprosus.ru/user-story-methodology?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=leprosus"></link><title>Методология User Story</title><published>2024-11-14T20:28:15.681Z</published><updated>2024-11-15T09:51:58.335Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/bb/ee/bbee2527-796e-44d5-9f47-17cd6d8f80fc.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/5e/46/5e46d3b0-5cf1-4eaf-9f49-1d85face717e.jpeg&quot;&gt;User Story (пользовательская история) - это методология, используемая в разработке программного обеспечения для описания функциональных требований с точки зрения конечного пользователя.</summary><content type="html">
  &lt;p id=&quot;SStF&quot;&gt;&lt;strong&gt;User Story (пользовательская история)&lt;/strong&gt; - это методология, используемая в разработке программного обеспечения для описания функциональных требований с точки зрения конечного пользователя.&lt;/p&gt;
  &lt;figure id=&quot;O7qo&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5e/46/5e46d3b0-5cf1-4eaf-9f49-1d85face717e.jpeg&quot; width=&quot;4000&quot; /&gt;
    &lt;figcaption&gt;Когда по привычке бумагу используешь по назначению&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;f6jc&quot;&gt;Подход помогает командам сосредоточиться на потребностях пользователей и создавать более ценные и удобные продукты.&lt;/p&gt;
  &lt;p id=&quot;RjsM&quot;&gt;Также повышается прозрачность передачи информации от заказчика вперёд по цепочке производства вплоть до доставки функциональности на прод.&lt;/p&gt;
  &lt;h2 id=&quot;Zsnn&quot;&gt;Проблемы ТЗ для продуктовой разработки&lt;/h2&gt;
  &lt;ol id=&quot;wXlO&quot;&gt;
    &lt;li id=&quot;wyyX&quot;&gt;&lt;strong&gt;Потеря ценности&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;9AIo&quot;&gt;
      &lt;li id=&quot;rE9D&quot;&gt;При передаче бизнес требований от одного человека к другому низкоописанные требования будут заполнены фантазиями и галюцинациями исполнителя.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;VSHt&quot;&gt;&lt;strong&gt;Трата времени&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;P8sP&quot;&gt;
      &lt;li id=&quot;loCn&quot;&gt;Для повышения понимания поставленной задачи исполнителям нужно будет больше коммуницировать с заказчиком.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;hHc7&quot;&gt;&lt;strong&gt;Потеря качества&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;qnuH&quot;&gt;
      &lt;li id=&quot;7kfv&quot;&gt;Невозможно низкодекомпозированную задачу реализовать без потери всех аспектов.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;7gdt&quot;&gt;Основные компоненты User Story&lt;/h2&gt;
  &lt;p id=&quot;7Nli&quot;&gt;Пользовательская история обычно включает следующие элементы:&lt;/p&gt;
  &lt;ol id=&quot;SB0w&quot;&gt;
    &lt;li id=&quot;zwSq&quot;&gt;&lt;strong&gt;Роль пользователя&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;57x9&quot;&gt;
      &lt;li id=&quot;I6hg&quot;&gt;Кто является конечным пользователем (например: покупатель, продавец-консультант).&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;ltCh&quot;&gt;&lt;strong&gt;Действие&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;buhB&quot;&gt;
      &lt;li id=&quot;Ud7Z&quot;&gt;Что пользователь хочет сделать (например: купить товар со скидкой 11.11, повысить продажи во время акции 11.11).&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;0tm3&quot;&gt;&lt;strong&gt;Цель&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;IEAR&quot;&gt;
      &lt;li id=&quot;m7TB&quot;&gt;Зачем это нужно пользователю (например: закрыть потребность меньшими затратами, обеспечить уровень продаж в низкий сезон).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;c3Pt&quot;&gt;Дополнительно, каждая история должна содержать критерии приемки, которые определяют условия, при которых задача считается выполненной.&lt;/p&gt;
  &lt;h2 id=&quot;jFtW&quot;&gt;Принципы написания User Story&lt;/h2&gt;
  &lt;p id=&quot;zeKC&quot;&gt;Для создания эффективных пользовательских историй часто используется акроним &lt;strong&gt;INVEST&lt;/strong&gt;:&lt;/p&gt;
  &lt;ul id=&quot;OuuZ&quot;&gt;
    &lt;li id=&quot;Kn5l&quot;&gt;&lt;strong&gt;Independent (Независимость)&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;7SP4&quot;&gt;
      &lt;li id=&quot;gAWc&quot;&gt;Истории должны быть независимыми друг от друга.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;IGEO&quot;&gt;&lt;strong&gt;Negotiable (Обсуждаемость)&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;5XnR&quot;&gt;
      &lt;li id=&quot;tCri&quot;&gt;Истории должны быть гибкими и поддаваться изменениям.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;rmB1&quot;&gt;&lt;strong&gt;Valuable (Ценность)&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;Wq3H&quot;&gt;
      &lt;li id=&quot;7aZA&quot;&gt;Каждая история должна приносить реальную/оцениваемую ценность пользователю.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;j7OR&quot;&gt;&lt;strong&gt;Estimable (Оценимость)&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;d1ZI&quot;&gt;
      &lt;li id=&quot;tngo&quot;&gt;Команды должны быть в состоянии оценить время и усилия для реализации без доп консультаций во время реализации.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;hN0p&quot;&gt;&lt;strong&gt;Small (Маленькие)&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;xUP5&quot;&gt;
      &lt;li id=&quot;odVU&quot;&gt;Истории должны быть небольшими и реализуемыми в рамках одной итерации/спринта.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;0qC6&quot;&gt;&lt;strong&gt;Testable (Тестируемость)&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;DuZH&quot;&gt;
      &lt;li id=&quot;e52R&quot;&gt;Наличие четких критериев приемки для проверки успешности выполнения.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;59GV&quot;&gt;Процесс создания User Story&lt;/h2&gt;
  &lt;ol id=&quot;UNVg&quot;&gt;
    &lt;li id=&quot;u1bS&quot;&gt;&lt;strong&gt;Определение целевой аудитории&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;hWMt&quot;&gt;
      &lt;li id=&quot;nMOf&quot;&gt;Понимание, для кого создается продукт.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;MvQe&quot;&gt;&lt;strong&gt;Выявление потребностей пользователей&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;Cr6t&quot;&gt;
      &lt;li id=&quot;RBWi&quot;&gt;Сбор информации через интервью и опросы.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;tEni&quot;&gt;&lt;strong&gt;Создание списка User Stories&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;5n8G&quot;&gt;
      &lt;li id=&quot;wF37&quot;&gt;Формулирование кратких описаний функциональности.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;yvNc&quot;&gt;&lt;strong&gt;Приоритизация историй&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;9iKJ&quot;&gt;
      &lt;li id=&quot;94We&quot;&gt;Определение наиболее важных задач для пользователей и бизнеса.&lt;/li&gt;
      &lt;li id=&quot;XFMx&quot;&gt;Приоритизация должны строиться на основании одного из методов, исключая субъективизм.&lt;/li&gt;
      &lt;li id=&quot;Tgm5&quot;&gt;Список методов можно &lt;a href=&quot;https://vc.ru/marketing/274778-12-metodov-prioritizacii-produktovyh-celei-rice-wsjf-kano-i-prochie&quot; target=&quot;_blank&quot;&gt;почитать тут&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;ka65&quot;&gt;&lt;strong&gt;Детализация описаний&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;3QEr&quot;&gt;
      &lt;li id=&quot;jIhp&quot;&gt;Добавление конкретных неделимых шагов и условий для каждой истории.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;zyoM&quot;&gt;Преимущества использования User Story&lt;/h2&gt;
  &lt;ol id=&quot;3NGV&quot;&gt;
    &lt;li id=&quot;pyDc&quot;&gt;&lt;strong&gt;Улучшение коммуникации&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;pDFw&quot;&gt;
      &lt;li id=&quot;VRZl&quot;&gt;User Stories способствуют лучшему пониманию требований между командами разработки и заинтересованными сторонами.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;cn5f&quot;&gt;&lt;strong&gt;Итеративная разработка&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;1HER&quot;&gt;
      &lt;li id=&quot;16Xj&quot;&gt;Истории помогают разбить проект на управляемые части, что упрощает процесс разработки в рамках Agile-методологий.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;u1bb&quot;&gt;&lt;strong&gt;Фокус на пользователе&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;24xf&quot;&gt;
      &lt;li id=&quot;18ns&quot;&gt;Этот подход позволяет командам лучше понимать ожидания клиентов и адаптировать продукт под их нужды.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;eh5b&quot;&gt;Хорошие пользовательские истории&lt;/h2&gt;
  &lt;ol id=&quot;yA3z&quot;&gt;
    &lt;li id=&quot;RadS&quot;&gt;Я, как пользователь сайта, хочу иметь возможность детально принимать результат рассчёта скидок по акции 11.11&lt;/li&gt;
    &lt;li id=&quot;GQxU&quot;&gt;Я, как пользователь, хочу иметь возможность добавлять товар в список избранных, для того чтобы в дальнейшем быстро находить его.&lt;/li&gt;
    &lt;li id=&quot;1Nte&quot;&gt;Я, как пользователь панели с правами супер-админа, хочу иметь возможность посмотреть список администраторов системы, для того чтобы наглядно видеть тех, кто имеет к ней доступ.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;Ndm5&quot;&gt;Плохие пользовательские истории&lt;/h2&gt;
  &lt;ol id=&quot;zY9v&quot;&gt;
    &lt;li id=&quot;jPbD&quot;&gt;Создать страницу товара.&lt;/li&gt;
    &lt;li id=&quot;uPHU&quot;&gt;Добавить функциональность поиска.&lt;/li&gt;
    &lt;li id=&quot;nCME&quot;&gt;Как пользователь, я хочу, чтобы продукт был лучше.&lt;/li&gt;
    &lt;li id=&quot;7UvP&quot;&gt;Я, как администратор системы, хочу иметь возможность добавлять, редактировать и удалять категории товаров, фильтровать и сортировать их. Я также хочу настраивать права доступа к этим функциям для разных ролей.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;Ueez&quot;&gt;Визуализация User Story&lt;/h2&gt;
  &lt;p id=&quot;yV4g&quot;&gt;Для этого существуют несколько подходов, один из самых простых - &lt;strong&gt;User Story Mapping (Карта Пользовательских Историй)&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;vZOn&quot;&gt;&lt;strong&gt;USM&lt;/strong&gt; - это метод визуализации, основанный на User Stories.&lt;/p&gt;
  &lt;figure id=&quot;40CG&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/da/4b/da4bda16-c65d-43d4-94f7-40122f642024.png&quot; width=&quot;2434&quot; /&gt;
    &lt;figcaption&gt;Когда GuanoStick тоже инструмент&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XqFf&quot;&gt;Какие действия необходимо выполнить:&lt;/p&gt;
  &lt;ol id=&quot;gRRv&quot;&gt;
    &lt;li id=&quot;SrO5&quot;&gt;В любом удобном инструменте (&lt;em&gt;Google Sheets&lt;/em&gt;, &lt;em&gt;MS Excel&lt;/em&gt;, либо специализированных, подготовить шаблон, &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1TM1zWtsUYmdToLr3LOoASLIrUwODFuqsRNfla_Bj3rc&quot; target=&quot;_blank&quot;&gt;вот тут можно забрать пример&lt;/a&gt;);&lt;/li&gt;
    &lt;li id=&quot;Y1N5&quot;&gt;Перенести в строку &lt;strong&gt;Users&lt;/strong&gt; ранее выявленные пользовательские роли;&lt;/li&gt;
    &lt;li id=&quot;r9mp&quot;&gt;Перенести в строку &lt;strong&gt;Actions&lt;/strong&gt; ранее выявленные действия: для каждой роли реализуемых действий может быть несколько;&lt;/li&gt;
    &lt;li id=&quot;3rFM&quot;&gt;Для каждого действия заполнить историю;&lt;/li&gt;
    &lt;li id=&quot;zCLq&quot;&gt;Декомпозировать реализацию истории на цепочку понятных неделимых действий;&lt;/li&gt;
    &lt;li id=&quot;GspQ&quot;&gt;Разбить реализацию таким образом, чтобы действия умещались в возможности команды в рамках релизного цикла.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;minA&quot;&gt;В результате получается понятный, хорошо декомпозированный план, который можно передать в команду производства для реализации без риска столкнуться с неоднозначным прочтением требований&lt;/p&gt;

</content></entry><entry><id>leprosus:dry-principle</id><link rel="alternate" type="text/html" href="https://leprosus.ru/dry-principle?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=leprosus"></link><title>Принцип DRY - Don’t Repeat Yourself</title><published>2024-11-12T20:38:39.769Z</published><updated>2024-11-20T14:54:46.983Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/5d/5c/5d5c66af-212a-4c59-a60b-7c29ef4f8e52.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/60/5d/605d3b63-3572-4046-9a2e-1197297b56ee.jpeg&quot;&gt;В чём суть: необходимо избегать повторений одного и того же кода.</summary><content type="html">
  &lt;p id=&quot;mIDQ&quot;&gt;В чём суть: необходимо избегать повторений одного и того же кода.&lt;/p&gt;
  &lt;p id=&quot;6RUF&quot;&gt;И казалось бы, тут всё просто и можно на этом пост завершить. Но вы даже представить себе не можете, как часто этот принцип нарушается даже разработчиками, занимающими высокие позиции в компаниях.&lt;/p&gt;
  &lt;figure id=&quot;IWGp&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/60/5d/605d3b63-3572-4046-9a2e-1197297b56ee.jpeg&quot; width=&quot;2000&quot; /&gt;
    &lt;figcaption&gt;Когда горит жопа у плохого разработчика от своего же кода&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;gxus&quot;&gt;Ретроспектива&lt;/h2&gt;
  &lt;p id=&quot;CTPI&quot;&gt;Впервые принцип был описан &lt;strong&gt;Энди Хантом&lt;/strong&gt; и &lt;strong&gt;Дэйвом Томасом&lt;/strong&gt; в книге «Программист-прагматик: путь от подмастерья к мастеру» 1999 года &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Pragmatic_Programmer&quot; target=&quot;_blank&quot;&gt;ISBN 978-0135957059&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;ykXi&quot;&gt;Данный принцип по сути переосмысление &lt;strong&gt;SSOT&lt;/strong&gt; - &lt;strong&gt;Single Source Of Truth&lt;/strong&gt;.&lt;/p&gt;
  &lt;blockquote id=&quot;ci6u&quot;&gt;&lt;strong&gt;Википедия: &lt;/strong&gt;В проектировании и теории информационных систем единый источник истины (&lt;strong&gt;SSOT&lt;/strong&gt;) – это практика структурирования информационных моделей и схемы данных, которая подразумевает, что все фрагменты данных обрабатываются (или редактируются) только в одном месте. &lt;strong&gt;SSOT&lt;/strong&gt; предоставляют достоверные, актуальные и пригодные к использованию данные.&lt;/blockquote&gt;
  &lt;h2 id=&quot;jzzj&quot;&gt;Причина появления&lt;/h2&gt;
  &lt;ul id=&quot;Guz2&quot;&gt;
    &lt;li id=&quot;FR4S&quot;&gt;Автор кода обладает низкими профессиональными навыками&lt;/li&gt;
    &lt;li id=&quot;c5z7&quot;&gt;Чаще всего дубли кода появляются в случае, когда разработчик слабо знаком с изменяемой им системой&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;21tc&quot;&gt;Почему повторяемый код плох&lt;/h2&gt;
  &lt;ol id=&quot;SkVE&quot;&gt;
    &lt;li id=&quot;eXlr&quot;&gt;&lt;strong&gt;Сложность сопровождения&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;fejL&quot;&gt;
      &lt;li id=&quot;P4oi&quot;&gt;Автору кода необходимо держать в памяти все места дублей, когда требуется сделать модификацию одного из, иначе поведение в одном блоке изменится, в оставшихся нет.&lt;/li&gt;
      &lt;li id=&quot;ggad&quot;&gt;Если же код сопровождает не автор, то уровень сложности возрастает кратно, так как кроме описанного выше, разработчику придётся ещё догадаться, что код требует изменение кода в нескольких блоках.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;rJ3K&quot;&gt;&lt;strong&gt;Стоимость разработки/сопровождения&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;9MIx&quot;&gt;
      &lt;li id=&quot;EHQD&quot;&gt;Для реализации кода нужно потратить больше времени на дублирование&lt;/li&gt;
      &lt;li id=&quot;jwIF&quot;&gt;Нужно потратить больше времени для изменение кода, а время разработчика стоит дорого&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;kESl&quot;&gt;&lt;strong&gt;Когнитивное усложнение кода&lt;/strong&gt;&lt;/li&gt;
    &lt;ul id=&quot;kQAA&quot;&gt;
      &lt;li id=&quot;3cC1&quot;&gt;Читать мутную кодовую базу с дублями для мозга сильно непростая задача&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;4nDI&quot;&gt;Как можно обнаружить проблему&lt;/h2&gt;
  &lt;ul id=&quot;whH7&quot;&gt;
    &lt;li id=&quot;IcUh&quot;&gt;Популярные IDE могут показывать дубли кода&lt;/li&gt;
    &lt;li id=&quot;hHgs&quot;&gt;Изменяя алгоритм или поведение, приходится менять код в нескольких местах&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;G60h&quot;&gt;Как исправить проблему&lt;/h2&gt;
  &lt;ul id=&quot;0jlv&quot;&gt;
    &lt;li id=&quot;hVvE&quot;&gt;Применять правило &amp;quot;осмотритесь&amp;quot;: перед реализацией нужно убедиться, что новая функциональность ещё не была реализована&lt;/li&gt;
    &lt;li id=&quot;FaVH&quot;&gt;Просканировать код средствами статического анализатора кода, коих во всех языках достаточно, и выискать дубли&lt;/li&gt;
    &lt;li id=&quot;rEww&quot;&gt;Вынести дублируемый код в отдельную функцию и в местах дублирования использовать уже эту функцию&lt;/li&gt;
    &lt;li id=&quot;T4NQ&quot;&gt;Если же код сложнее, чем вынос в отдельную функцию, следует подобрать абстракцию&lt;/li&gt;
  &lt;/ul&gt;

</content></entry></feed>