/
Блог
/
Код
/

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

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

6 марта 2020 г.
2 минуты
66

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

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

Подписывайтесь на канал Кирилла Мокевнина в Telegram — чтобы узнать больше о программировании и профессиональном пути разработчика

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

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

5 лет назад

66