🗓️ 2024. 03. 17
⏱️ 10

Node.js로 만드는 CLI 클라이언트 1편 - UI

CLI에서 UI를 추구하면 안 되는 걸까

글을 쓰게된 배경

최근에 저는 의료 도메인에서 프로젝트를 진행중입니다.
의료 도메인에서 가장 민감한 사안이 보안인 만큼, 의료 도메인의 정책과 네트워크는 폐쇄적인 특성을 띠고 있습니다.
그런 폐쇄적인 특성 탓에 병원 내부에 도입될 프로그램 또한 로컬 환경에서 구동될 필요가 있었습니다.

이를 위해 이번 프로젝트에서는 Node.js 기반의 CLI 클라이언트를 제작했는데요,
제작 과정에서 있었던 러닝 포인트와 고민들을 2개의 편으로 나누어 공유드리려 합니다.

첫 번째 편인 이번 글에선 클라이언트와 별개로 CLI 환경에서 UI를 표현하는 방법을 소개합니다.
아주아주 쉬우니 편안하게 읽으시면 됩니다 :)

이번 글에서 다루는 내용

  • CLI와 GUI 소개
  • CLI에서 사용자와 상호작용하기

두 번째 편에선 본격적으로 CLI 환경의 클라이언트를 소개합니다.
왜 클라이언트 환경으로 GUI 대신 CLI를 선택했는지, 어떤 고민들이 필요했는지와 같은 복잡하고 어려운 내용들은 두 번째 편에서 다룰 예정입니다.

다음 글에서 다룰 내용

  • 클라이언트의 개념
  • CLI 클라이언트와 GUI 클라이언트의 장단점
  • CLI 클라이언트로 결정한 이유
  • CLI 클라이언트의 구성 요소
  • CLI 클라이언트 제작

CLI와 GUI

CLI

CLI(Command Line Interface)는 텍스트 기반의 명령어로 동작합니다. 터미널이나 콘솔을 통해 사용자와 상호작용하며, 개발자들에게 익숙한 git, npm, pip 같은 툴들이 CLI 프로그램에 해당됩니다.

흔히 떠올리는 까만 화면에 하얀 글씨가 CLI 프로그램입니다.흔히 떠올리는 까만 화면에 하얀 글씨가 CLI 프로그램입니다.

GUI

GUI(Graphical User Interface)는 그래픽 요소로 동작합니다. 사용자가 아이콘, 메뉴, 버튼 등을 마우스로 클릭해 상호작용하며, 개발자가 아닌 분들께 익숙한 프로그램들이 보통 GUI 프로그램에 해당됩니다.

대표적인 GUI 클라이언트, 웹브라우저대표적인 GUI 클라이언트, 웹브라우저
또 다른 대표적인 예시인 게임 클라이언트또 다른 대표적인 예시인 게임 클라이언트

인터페이스

CLI와 GUI는 공통적으로 Interface라는 정의를 포함합니다. 인터페이스(Interface)는 상호작용을 위한 접점 또는 매개체를 의미하는데요, 위에서 살펴본 각각의 정의에서 알 수 있듯이 사용자와 시스템이 어떻게 상호작용할 것인지가 CLI와 GUI를 구분짓습니다.

다시 말해, 사용자와 시스템이 상호작용할 수 있는 입출력 수단텍스트 기반인지 그래픽 기반인지가 CLI와 GUI를 결정합니다.

CLI 환경의 상호작용

용어를 모두 파악했으니 이제 CLI 환경에서 어떻게 사용자에게 인터페이스를 제공할 수 있는지 알아보겠습니다.

프로그램의 결과를 제공할 출력

  • 내장 기능
    가장 손쉽게 사용자에게 결과를 제공하는 방법은 console 객체를 이용하는 방법입니다.

    console.log("Hello, World!");
    

    하지만 터미널 상의 출력을 제어하고 싶다면 표준 출력인 process.stdout을 활용하는 편이 좋습니다.
    process.stdoutconsole.log처럼 결과를 출력할 수 있을 뿐만 아니라 여러 유틸리티 메서드도 제공합니다.
    Node.js의 TTY 공식 문서에서 더 자세히 다루고 있으니 한번쯤 살펴보시면 좋습니다.

    process.stdout.write('First Line\n'); // First Line 출력 후 줄바꿈
    process.stdout.write('Second Line\n'); // Second Line 출력 후 줄바꿈
    process.stdout.write('Third Line'); // Third Line 출력
    
    process.stdout.moveCursor(0, -1); // 터미널 커서를 한 칸 위로 올린다 (Second Line이 출력된 위치)
    process.stdout.clearLine(0); // 현재 커서가 위치한 줄을 모두 지운다
    
    process.stdout.moveCursor(0, 2); // 커서를 다시 2칸 내린다
    

    이 코드의 수행 결과는 다음과 같습니다.

    First Line
    
    Third Line
    
  • figlet
    figlet은 아스키 문자열로 배너를 만들어주는 프로그램입니다.
    사용자에게 프로그램의 이름을 표시해주거나 눈에 띄는 가이드를 제공할 때 유용하게 쓰입니다.

    원래 figlet은 UNIX 기반 OS의 터미널 환경에서 사용할 수 있기 때문에 aptbrew를 통해 설치 가능합니다.
    node.js에선 동명의 라이브러리를 설치해 사용할 수 있습니다.

    npm install figlet
    
    import figlet from 'figlet';
    
    const banner = figlet.textSync('verycosy');
    process.stdout.write(banner);
    
    __   _____ _ __ _   _  ___ ___  ___ _   _ 
    \ \ / / _ \ '__| | | |/ __/ _ \/ __| | | |
     \ V /  __/ |  | |_| | (_| (_) \__ \ |_| |
      \_/ \___|_|   \__, |\___\___/|___/\__, |
                    |___/               |___/
    
  • chalk
    chalk는 단어 그대로 터미널에 출력된 텍스트에 색을 입혀주는 라이브러리입니다.
    최신 버전인 v5부터는 ESM으로만 제공됩니다. (공식 문서 참조)

    npm install chalk
    
    import chalk from 'chalk';
    
    const log = console.log;
    
    log(chalk.blue('Hello') + ' World' + chalk.red('!'));
    log(chalk.blue.bgRed.bold('Hello world!'));
    log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz'));
    log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!'));
    log(
        chalk.green(
            'I am a green line ' +
            chalk.blue.underline.bold('with a blue substring') +
            ' that becomes green again!'
        )
    );
    
    색깔을 통해 사용자에게 정보를 더 확실히 인지시킬 수 있습니다.색깔을 통해 사용자에게 정보를 더 확실히 인지시킬 수 있습니다.
  • ora
    ora는 터미널에서 스피너 애니메이션을 제공해줍니다. 비동기 동작이 진행중임을 나타낼 때 유용합니다.
    chalk와 마찬가지로 ESM만 제공됩니다.

    npm install ora
    
    import ora from 'ora';
    
    const spinner = ora('Loading unicorns').start();
    setTimeout(() => {
    spinner.color = 'yellow';
    spinner.text = 'Loading rainbows';
    }, 1000);
    
    터미널에서 로딩 상태를 표현할 수 있습니다.터미널에서 로딩 상태를 표현할 수 있습니다.

프로그램을 수행시킬 입력

  • 내장 기능
    표준 출력과 달리 표준 입력으로 터미널을 다룰 땐 process.stdin보다 내장 라이브러리인 readline을 활용하는 게 더 편리합니다. 간단하게 사용자로부터 텍스트를 입력받는 예제를 작성해보겠습니다.

    import readline from 'node:readline';
    
    const cli = readline.createInterface({
        input: process.stdin, // 표준 입력 스트림을 입력 매체로 사용
        output: process.stdout, // 표준 출력 스트림을 출력 매체로 사용
    });
    
    cli.question('닉네임은? ', (nickname) => {
        console.log(`사용자의 닉네임 : ${nickname}`);
        cli.close();
    });
    
    닉네임은? verycosy
    사용자의 닉네임 : verycosy
    

    Node.js의 readline 공식 문서에서 터미널 커서 관리를 비롯한 유틸리티 메서드를 확인할 수 있습니다.

  • @inquirer
    inquirer는 인터랙티브한 CLI 인터페이스를 만들어주는 라이브러리입니다.
    사용자에게 텍스트 입력뿐만 아니라 Select, Checkbox, Password 등의 인터페이스를 손쉽게 제공할 수 있습니다.

    npm install @inquirer/prompts
    
    import { input, select, checkbox } from '@inquirer/prompts';
    
    const nickname = await input({ message: '닉네임' });
    const food = await select({
        message: '좋아하는 음식',
        choices: [
            { value: '한식' },
            { value: '중식' },
            { value: '일식' },
            { value: '양식' },
        ],
    });
    
    const checkedItems = await checkbox({
        message: '필요한 일회용품',
        choices: [
            { value: '플라스틱 수저' },
            { value: '나무젓가락' },
            { value: '물티슈' },
        ],
    });
    
    웹과 앱에서 자주 사용되는 UI를 표현할 수 있습니다.웹과 앱에서 자주 사용되는 UI를 표현할 수 있습니다.

다음 편 예고

이번 글에선 CLI 환경에서 사용자에게 제공할 수 있는 인터페이스와 그 방법을 알아봤습니다.
다음 편에서는 소개드린 내용을 활용해 본격적으로 CLI 클라이언트 프로그램을 작성해보겠습니다.

돌아가기
© 2024 VERYCOSY.