Все статьи | Разработка

Совершенный код: поддержка кроссплатформенности

Совершенный код: поддержка кроссплатформенности главное изображение

Кроссплатформенность — способность программы запускаться на разных платформах, например, разных операционных системах. Это довольно важное качество для программ, которые нужно запускать и в Windows, и в Linux. Причем как со стороны пользователей (все хотят кроссплатформенный фотошоп), так и со стороны разработчиков. Последнее часто встречается в веб-разработке, где часть команды может использовать одну операционную систему, а часть — другую.

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

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

import fs from 'fs';

// Не забывайте что абстракции текут, в определенных моментах различия все же есть
fs.readFileSync('filename');

Но есть определенные вещи, которые спрятать нельзя, и программисту приходится работать с ними напрямую. Возьмем для примера разделитель директорий. В Windows это \ обратный слеш (backslash), в Linux – / прямой слеш или просто слеш. Какой использовать? Попробуем разобраться.

Разделитель директорий

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

import path from 'path';

console.log(path.sep);
// В Linux: /
// В Macos: /
// В Windows: \

path.join('one', 'two', 'three');
// Внутри делает ['one', 'two', 'three'].join(path.sep);
// В Linux: one/two/three
// В Macos: one/two/three
// В Windows: one\two\three

Решение кажется очевидным: достаточно начать использовать path.sep в тех местах, где идет работа с путями, и вопрос исчерпан. Да, для подавляющего большинства ситуаций такой ход сработает, но не для всех. Представьте, что наша программа должна формировать конфигурационный json-файл, внутри которого есть пути:

{
    "manifest": "public/assets/manifest.json"
}

Затем этот файл будет использоваться на самом сайте (в продакшене). В подавляющем большинстве случаев продакшен (место где запускается сайт) работает на Linux. Это значит, что если файл был сформирован в Windows-среде, то он не заработает в Linux-среде, так как Linux не понимает обратные слеши (как и MacOS). Что делать в этой ситуации?

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

Перевод строки

Другой пример — перевод строки. В большинстве операционных систем для перевода строк используется \n, но только не в Windows. Там по историческим причинам перевод строки — это \r\n. И это уже действительно проблема, потому что касается не только того, как работает код, но и в принципе самого исходного кода. Каждый файл, который сохраняется в Windows, будет сохраняться с \r\n в конце каждой строки. Это приводит к куче разных проблем:

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

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

import os from 'os';

console.log(os.EOL);
// В Linux: \n
// В Macos: \n
// В Windows: \r\n

Как раз этот подход приводит к проблемам, указанным выше.

Второй подход — всегда использовать \n. Ситуация здесь аналогична разделителю директорий. \n — универсальный символ, одинаково хорошо работает и в Windows, и в остальных операционных системах:

lines = ['one', 'two', 'three'];
const text = lines.join('\n');
// one
// two
// three

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

Дополнительные материалы:

Аватар пользователя Kirill Mokevnin
Kirill Mokevnin 06 марта 2020
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
22 сентября 8 месяцев
Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
22 сентября 8 месяцев
Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
22 сентября 8 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
22 сентября 8 месяцев
Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
22 сентября 10 месяцев
Иконка программы Разработчик на Ruby on Rails
Профессия
Новый
Создает веб-приложения со скоростью света
22 сентября 5 месяцев