Несколько лет назад я прочитал книгу «Путь «Тойоты», руководствуясь интересом к истокам разработки программного обеспечения Agile. Однако еще больше меня заинтриговали производственные процессы «Тойоты» и принципы повышения их эффективности. В книге содержалось множество ценных идей и практик, которые можно было взять на вооружение. Меня, как разработчика, особенно привлекли 5 S-принципов. Я понял, что мы часто применяем большинство из этих принципов в работе, хотя и не систематически.

5 S-принципов, заимствованных из сферы бережливого производства, — это японская методология, направленная на повышение эффективности и производительности за счет систематической организации. Вот эти принципы — Sort («Сортировка»), Set in Order  («Приведение в порядок»), Shine («Очистка»), Standardize («Стандартизация») и Sustain («Поддержание»)

В этой статье мы рассмотрим, как каждый из пяти S-принципов можно применить к практике написания кода на примере JavaScript. Мы обсудим практическую реализацию, инструменты, которые помогут в этом процессе, и то, как интегрировать указанные принципы в рабочий процесс разработки. К концу статьи вы получите полное представление о том, каким образом 5 S-принципов способны усовершенствовать практику программирования и как они помогут создавать более чистый, эффективный и удобный в обслуживании код.

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

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

1. Sort («Сортировка»). Удаляйте ненужные элементы из рабочего пространства

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

Выявление неиспользуемого кода

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

До:

// Неиспользуемая функция
function unusedFunction() {
console.log('This is never used');
}

// const request = new Request("https://example.org/post", {
// метод: "POST",
// тело: JSON.stringify({ username: "example" }),
// });

// Основная функция
function mainFunction() {
console.log('This function is used');
}

mainFunction();
import React from 'react';
import { useState } from 'react';
import { unusedFunction } from './utils';

const MyComponent = () => {
const [state, setState] = useState(0);

return <div>{state}</div>;
};

export default MyComponent;

После: 

// Основная функция
function mainFunction() {
console.log('This function is used');
}

mainFunction();
import React from 'react';
import { useState } from 'react';

const MyComponent = () => {
const [state, setState] = useState(0);

return <div>{state}</div>;
};

export default MyComponent;

Выявление и удаление неиспользуемых зависимостей

Инструменты типа depcheck помогут найти неиспользуемые пакеты npm в проекте.

npx depcheck
Unused dependencies
* lodash
npm uninstall lodash

2. Set in Order («Приведение в порядок»). Организуйте элементы для обеспечения эффективности рабочего потока

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

Организуйте структуру проекта

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

project/
├── src/
│ ├── components/
│ │ ├── atoms/
│ │ │ └── Button.tsx
│ │ ├── molecules/
│ │ │ └── Form.tsx
│ │ ├── organisms/
│ │ │ └── Header.tsx
│ │ ├── templates/
│ │ │ └── PageTemplate.tsx
│ │ └── pages/
│ │ └── HomePage.tsx
│ ├── assets/
│ │ ├── images/
│ │ └── styles/
│ ├── utils/
│ │ └── helpers.ts
│ └── App.ts
├── public/
│ └── index.html
├── package.json
└── README.md

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

src/

├── features/
│ ├── UserManagement/
│ │ ├── components/
│ │ │ ├── UserProfile.tsx
│ │ │ ├── UserList.tsx
│ │ │ └── UserForm.tsx
│ │ ├── hooks/
│ │ │ ├── useUserData.ts
│ │ │ └── useUserList.ts
│ │ ├── api/
│ │ │ └── userApi.ts
│ │ ├── utils/
│ │ │ └── userFormatters.ts
│ │ └── index.ts
│ │
│ ├── Authentication/
│ │ ├── components/
│ │ │ ├── LoginForm.tsx
│ │ │ └── RegistrationForm.tsx
│ │ ├── hooks/
│ │ │ └── useAuth.ts
│ │ ├── api/
│ │ │ └── authApi.ts
│ │ ├── utils/
│ │ │ └── authValidators.ts
│ │ └── index.ts
│ │
│ └── Dashboard/
│ ├── components/
│ │ ├── DashboardLayout.tsx
│ │ ├── AnalyticsWidget.tsx
│ │ └── ActivityFeed.tsx
│ ├── hooks/
│ │ └── useDashboardData.ts
│ ├── api/
│ │ └── dashboardApi.ts
│ ├── utils/
│ │ └── dashboardHelpers.ts
│ └── index.ts

├── shared/
│ ├── components/
│ │ ├── Button.tsx
│ │ ├── Input.tsx
│ │ └── Modal.tsx
│ ├── hooks/
│ │ └── useForm.ts
│ └── utils/
│ ├── formatters.ts
│ └── validators.ts

├── App.ts
└── index.ts

Плоская структура:

src/
├── components/
│ ├── Header.ts
│ ├── Footer.ts
│ └── Navigation.ts
├── pages/
│ ├── Home.ts
│ ├── About.ts
│ └── Contact.ts
├── utils/
│ └── helpers.ts
└── App.ts

Указанные выше примеры приведены только в демонстрационных целях

Помните: выбор оптимальной структуры зависит от конкретного проекта и команды. Одни предпочитают плоские структуры, в то время как другие считают полезными вложенные конструкции. Главное — обсудить и согласовать подход, который способен повысить производительность команды.

  • Рассмотрите компромиссные решения между глубоко вложенными структурами и плоскими конструкциями.
  • Используйте понятные, описательные имена для файлов и каталогов.
  • Убедитесь в том, что файлы и каталоги расположены логично для удобства доступа и сопровождения.
  • Размещайте служебные функции в каталоге utils.
  • Группируйте связанные компоненты в каталоге components, следуя принципу атомарного проектирования или другим шаблонам, которые подходят для ваших нужд.
  • Храните статические активы, такие как изображения и стили, в каталоге assets.

3. Shine («Очистка»). Очищайте рабочее пространство, чтобы соответствовать стандартам и выявлять проблемы

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

Форматирование и стилизация кода

Такие инструменты, как Prettier и ESLint, помогают обеспечить последовательное форматирование и качество кода.

// До форматирования
function fetchData(){
return fetch('https://api.example.com/data').then(response => response.json()).then(data => {console.log(data);});
}
// После форматирования с помощью Prettier
function fetchData() {
return fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
});
}

Оптимизация производительности

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

// Перед улучшением (нужна оптимизация)
function findMax(arr) {
let max = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
// После оптимизации
Math.max(...arr);

Регулярный рефакторинг

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

// Перед упрощением (нужен рефакторинг) 
function calculateTotalPrice(products) {
let totalPrice = 0;
for (let i = 0; i < products.length; i++) {
totalPrice += products[i].price;
}
return totalPrice;
}
// После рефакторинга
function calculateTotalPrice(products) {
return products.reduce((total, product) => total + product.price, 0);
}

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

4. Standardize («Стандартизация»). Устанавливайте стандарты и процедуры для поддержания организованности и эффективности

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

Соглашения об именовании

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

// Переменные и функции используют camelCase
const userName = 'JohnDoe';
let userAge = 30;

function fetchUserData() {
// Получение данных пользователя
}

const calculateRadius = () => { /* ... */ }
// Классы используют PascalCase

class UserProfile {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
// Константы используют UPPER_SNAKE_CASE
const MAX_RETRY_ATTEMPTS = 3;

Создание и использование руководств по стилю

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

Руководство по стилю Airbnb JavaScript: популярный гайд по стилю, который охватывает различные аспекты написания кода на JavaScript.

Руководство по стилю Google Typescript: руководство по стилю от Google, содержащее всеобъемлющие стандарты и практики написания кода для Typescript.

// До стандартизации
function fetchData(){
return fetch('https://api.example.com/data').then(response => response.json()).then(data => {console.log(data);});
}

// После стандартизации
function fetchData() {
return fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => {
console.log(data);
});
}

Последовательная обработка ошибок

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

// До стандартизации
function fetchData() {
return fetch('https://api.example.com/data')
.then((response) => response.json())
.catch((error) => {
console.error(error);
});
}

// После стандартизации
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}

Стандарты тестирования

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

Создавайте файлы тестов, используя согласованное именование, например filename.test.js:

// fetchData.test.js
const fetchData = require('./fetchData');

test('fetches data from API', async () => {
const data = await fetchData();
expect(data).toBeDefined();
});

Определение и установка порога покрытия кода

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

module.exports = {
collectCoverage: true,
coverageDirectory: 'coverage',
coverageProvider: 'v8',
coverageReporters: ['text', 'lcov', 'clover'],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
collectCoverageFrom: [
'src/**/*.{js,jsx,ts,tsx}',
'!src/**/*.d.ts',
'!src/index.tsx',
'!src/serviceWorker.ts',
],
};

Контроль версий с помощью Git

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

  • Ветви функций: feature/short-description.
  • Ветви исправлений: bugfix/short-description.
  • Ветви релизов: release/x.y.z.
main

feature/user-authentication
feature/dashboard-improvements

bugfix/login-error

release/1.0.0

5. Sustain («Поддержание»). Регулярно поддерживайте и пересматривайте стандарты, чтобы обеспечить их долгосрочное соблюдение

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

Git-хуки

Использование Git-хуков с помощью Husky позволяет автоматизировать проверки и задачи на разных этапах рабочего процесса Git. Это поможет поддерживать качество кода, обеспечивать прохождение тестов перед коммитами, а также внедрить соглашения о сообщениях коммитов в рамках команды.

// package.json

{
"scripts": {
"prepare": "husky install"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint && npm test",
"pre-push": "npm run build",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}

Непрерывная интеграция и непрерывное развертывание (CI/CD)

Реализуйте конвейеры CI/CD для обеспечения автоматического тестирования, интеграции и развертывания изменений кода. Ниже приведен пример для инструмента GitHub Actions.

Каждый запрос push или pull в ветку main должен запускать конвейер CI, обеспечивая автоматический запуск тестов и линтинга.

name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test

- name: Lint code
run: npm run lint

Документация по коду

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

/**
* Вычисляет площадь прямоугольника.
*
* @param {number} length - Длина прямоугольника.
* @param {number} width - Ширина прямоугольника.
* @returns {number} Площадь прямоугольника.
* @throws {Error} Если длина или ширина отрицательны.
*
* @example
* // возвращает 50
* calculateRectangleArea(10, 5);
*
* @since 1.0.0
* @author Jane Doe <jane@example.com>
*/
function calculateRectangleArea(length, width) {
if (length < 0 || width < 0) {
throw new Error('Length and width must be non-negative');
}
return length * width;
}

Регулярные проверки кода

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

Контрольный список для проверки кода:

  • Код соответствует руководству по стилю (например, Airbnb, Google).
  • Функциональность корректна и соответствует требованиям.
  • Код чистый, читаемый и поддерживаемый.
  • Есть всеобъемлющие тесты.
  • Учтены соображения производительности.

Постоянное обучение и адаптация

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

Следите за последними тенденциями, технологиями и передовым опытом разработки на JavaScript, используя онлайн-курсы, книги, видео и т. д. Участвуйте в сообществах JavaScript (например, Stack Overflow, GitHub). Посещайте конференции и встречи (JSConf, местные встречи JavaScript-разработчиков).

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

Помните, что цель 5 S-принципов в программировании — не достижение совершенства, а постоянное улучшение. Начните с малого — возможно, с внедрения линтера в проект или создания процесса проверки кода. Когда команда привыкнет к этим изменениям, постепенно внедряйте другие практики S-принципов.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Santhosh Sundar: Using the 5S principle in coding

Предыдущая статьяAngular: как с функцией inject() сэкономить 1000 строк кода