Page

관련 포스팅

2023년 10월 14일 토요일

프로그래밍 습관 교정 - 클라이언트 alert 및 커스텀 메시지 관리

어제 Internet Software Architecture lab을 marking 받으면서 받았던 피드백을 리뷰하면서 내가 실수했던 포인트와 깨달은 점들을 정리해보려 한다.


메시지 display 이슈 (Frontend vs. backend)

백엔드, 프론엔드 프로그램을 제작할 때, 발생하는 (대부분의) 메시지는 프론엔드 쪽에도 display를 해줘야 한다. 당연한 이야기지만, 클라이언트 측은 백엔드 로그를 절대로 볼 수가 없으니, 에러 혹은 워닝이 발생한 상황에서 메시지를 받지 못하면 이를 알 방법이 없다.

lab 검사를 받을 때는 당연히 백엔드 서버에 접속해서 그 log를 보여주면서 완성도를 어필할 수 있지만, 실제 field에 나가서는 그런것들이 전혀 의미가 없게된다. 이를 간과했다. warning이든, error든 client가 즉시 인지할 수 있도록 브라우저 사이드에서 메시지를 출력해줘야 하겠다. 여기서 console.log도 사실 의미가 없다.

커스텀 메시지 분리 이슈

이 항목이 lab requirement에 있었는데, 사실 대수롭지 않게 여기고 안일하게 넘어갔던 것이 문제였다. 서버측에서든 클라이언트 측에서든 내가 임의로 에러/경고 메시지를 생성하는 경우에는 이 메시지를 코드의 최상단에 배치하거나, 가급적이면 별도의 file로 관리를 하는 방식을 사용해야 한다.

즉, 사용자에게 보이는 문자열을 코드의 상단이나 별도의 파일에 저장해두는 것이 좋다는 의미다. 이렇게 하는 이유에는 여러 가지가 있다:

  1. 가독성: 사용자에게 보이는 문자열이 코드 내부에 섞여 있으면 코드를 읽기 어렵게 만든다. 별도의 위치에 문자열을 모아두면 코드의 가독성이 향상된다.

  2. 유지보수: 나중에 문자열을 수정해야 할 경우, 한 곳에서만 수정하면 된다. 문자열이 코드 여기저기에 퍼져 있다면, 같은 문자열을 찾아서 여러 번 수정해야 하므로 유지보수가 어려워진다.

  3. 다국어 지원(i18n): 애플리케이션을 여러 언어로 제공하려면 문자열을 별도로 관리하는 것이 효율적이다. 각 언어별로 다른 파일이나 설정을 사용할 수 있다.

  4. 재사용성: 같은 문자열이 여러 곳에서 사용될 수 있다. 문자열을 한 곳에 모아두면 여러 위치에서 쉽게 재사용할 수 있다.

  5. 테스트 용이성: 문자열을 별도로 관리하면, 자동화된 테스트를 작성할 때도 편리하다. 테스트 코드에서 해당 문자열을 쉽게 참조할 수 있다.

  6. 팀 작업: 별도의 파일에 문자열을 저장해두면, 개발자와 디자이너나 텍스트 작성자가 동시에 작업하기 쉽다. 개발자는 로직에 집중하고, 디자이너나 텍스트 작성자는 문자열에 집중할 수 있다.

이러한 이유로, 많은 프로젝트에서는 사용자에게 보이는 문자열을 별도의 파일이나 설정에 저장해 둔다.

따라서 지금까지 이 부분을 간과했는데, 이제부터는 좋은 코딩 습관을 형성하기 위해서 일부러라도 자꾸 되뇌이려 한다.


커스텀 메시지 구현 방법

당연히 방법은 여러가지가 있다. 아래는 내 사고의 흐름과 의문점을 해결해 나가는 과정에서 나온 질문과 답변들이다. 바로 방법을 제시하는 것보다는 이런식으로 흐름을 따라가는 것이 보다 근본적인 문제를 해결하고 또 응용하는데 도움이 될 것이라는 판단이다.

메시지를 정의한 파일을 생성하고 싶다.

JavaScript에서 별도의 파일에 커스텀 메시지를 정의하고 그것을 다른 파일에서 가져와 사용하는 방법은 여러 가지가 있다. CommonJS나 ES6 모듈을 사용하는 방법이 주로 쓰인다. 주력 언어가 Java라고 했으니, 모듈 시스템이 익숙할 테니 ES6 모듈을 예로 들겠다.

메시지를 정의한 파일 생성 (message.js)

// message.js
const messages = {
  hello: "안녕하세요",
  goodbye: "안녕히 가세요",
  welcome: "환영합니다"
};

export default messages;

메시지를 가져와 사용할 파일 (main.js)

// main.js
import messages from './message.js';

console.log(messages.hello);  // 출력: "안녕하세요"
console.log(messages.goodbye); // 출력: "안녕히 가세요"
console.log(messages.welcome); // 출력: "환영합니다"

이렇게 하면 main.js 파일에서 message.js 파일에 정의된 messages 오브젝트를 사용할 수 있다.

주의할 점:

  • 두 파일이 같은 디렉터리에 있거나, 상대 경로가 올바르게 설정되어 있어야 한다.
  • 이 기능은 브라우저가 ES6 모듈을 지원하는 경우나 Node.js에서 사용할 수 있다. 브라우저에서 사용할 경우, HTML 파일에서 type="module"을 설정해야 한다.
    <script type="module" src="main.js"></script>
    

이런 식으로 커스텀 메시지를 별도의 파일에 저장하고 필요한 곳에서 불러와 사용할 수 있다.

메시지를 정의하는 파일은 js여야 하나? 더 범용적이고 효율적인 형식의 파일은 없는가?

메시지를 정의하는 파일은 반드시 JS일 필요는 없다. 범용적이고 다른 언어나 플랫폼에서도 쉽게 사용할 수 있는 형식으로는 주로 JSON, XML, YAML, CSV, .env 등이 있다. 각 형식의 특성에 따라 적절한 것을 선택할 수 있다.

JSON

JSON 형식은 자바스크립트 오브젝트와 유사해서 자바스크립트에서 쉽게 사용할 수 있다. 다른 프로그래밍 언어에서도 JSON을 쉽게 파싱할 수 있다.

{
  "hello": "안녕하세요",
  "goodbye": "안녕히 가세요",
  "welcome": "환영합니다"
}

XML

XML은 범용적이며 복잡한 데이터 구조도 표현할 수 있다. 하지만 JSON보다는 무겁고 파싱하기 복잡할 수 있다.

<messages>
  <hello>안녕하세요</hello>
  <goodbye>안녕히 가세요</goodbye>
  <welcome>환영합니다</welcome>
</messages>

YAML

YAML은 가독성이 좋고 복잡한 데이터 구조를 표현할 수 있다. 하지만 파싱 라이브러리가 필요하다.

hello: "안녕하세요"
goodbye: "안녕히 가세요"
welcome: "환영합니다"

CSV

CSV는 가장 단순하고 가벼운 형식이지만, 복잡한 데이터 구조를 표현하기 어렵다.

key,value
hello,안녕하세요
goodbye,안녕히 가세요
welcome,환영합니다

.env

.env 파일은 주로 환경 변수를 설정할 때 사용한다. 메시지를 저장하기에는 적합하지 않을 수 있다.

HELLO=안녕하세요
GOODBYE=안녕히 가세요
WELCOME=환영합니다

이렇게 여러 형식이 있으니 상황에 따라 적절한 형식을 선택하면 된다. JSON이나 YAML은 복잡한 데이터 구조를 표현할 수 있으므로 메시지 외에도 여러 정보를 저장할 수 있다. XML은 범용적이지만 무겁고 파싱이 복잡하다. CSV는 가볍고 단순하지만 복잡한 데이터 구조를 표현하기 어렵다.

그렇다며면 JSON으로 하려고 한다. 이것을 javascript 및 html에서 사용할 수 있도록 하려면 어떻게 해야하나?

JSON 파일을 사용해 자바스크립트와 HTML에서 메시지 등을 활용하려면 여러 가지 방법이 있다. 여기서는 두 가지 방법을 소개하겠다: AJAX를 사용하는 방법과 fetch API를 사용하는 방법.

1. AJAX를 사용하는 방법

JQuery를 사용하고 있다면 AJAX를 이용해 JSON 파일을 불러올 수 있다.

$.getJSON("path/to/your/file.json", function(data) {
  // data는 JSON 파일의 내용을 파싱한 오브젝트
  console.log(data.hello); // "안녕하세요"
});

2. fetch API 사용

최신 브라우저에서는 fetch API를 사용해 비동기적으로 리소스를 불러올 수 있다.

fetch("path/to/your/file.json")
  .then(response => response.json())
  .then(data => {
    // data는 JSON 파일의 내용을 파싱한 오브젝트
    console.log(data.hello); // "안녕하세요"
  })
  .catch(error => console.error("데이터를 불러오는데 실패했다", error));

HTML에서 사용하기

HTML에서 사용하려면 불러온 메시지 데이터를 DOM에 적용하는 로직을 작성하면 된다. 예를 들어, 특정 요소의 텍스트를 변경할 수 있다.

fetch("path/to/your/file.json")
  .then(response => response.json())
  .then(data => {
    // data는 JSON 파일의 내용을 파싱한 오브젝트
    document.getElementById("welcomeMessage").textContent = data.welcome;
  })
  .catch(error => console.error("데이터를 불러오는데 실패했다", error));

HTML 코드 예시:

<div id="welcomeMessage"></div>

이런 식으로 JSON 파일을 불러와 원하는 로직에 적용할 수 있다.

import 형식으로는 JSON을 가져올 수 없나?

JavaScript 모듈 시스템을 사용하고 있다면, import 문을 이용해 JSON 파일을 불러올 수 있다. 이 방법은 주로 Node.js나 웹팩, 브라우저의 ES 모듈 기능을 사용하는 프론트엔드 프로젝트에서 유용하다.

다음과 같이 JSON 파일을 import할 수 있다.

// messages.json 파일
{
  "hello": "안녕하세요",
  "goodbye": "안녕히 가세요",
  "welcome": "환영합니다"
}

// JavaScript 파일
import messages from './messages.json';

console.log(messages.hello); // 출력: "안녕하세요"

이렇게 하면, JSON 파일의 내용이 자동으로 자바스크립트 오브젝트로 변환되어 messages 변수에 할당된다.

하지만 이 방법은 빌드 도구나 서버 없이 단순한 HTML과 자바스크립트만으로 작동하는 경우에는 사용할 수 없다. 이런 상황에서는 위에서 설명한 fetch나 AJAX 방법을 사용해야 한다.

"하지만 이 방법은 빌드 도구나 서버 없이 단순한 HTML과 자바스크립트만으로 작동하는 경우에는 사용할 수 없다." 이게 무슨 의미인가? 더 쉽고 자세하게 설명해줘

물론이다. "빌드 도구나 서버 없이 단순한 HTML과 자바스크립트만으로 작동하는 경우"라는 말은 웹사이트나 애플리케이션이 복잡한 설정이나 서버 없이 그냥 브라우저에서 HTML 파일을 열어서 작동하는 경우를 의미한다. 예를 들어, HTML 파일을 더블클릭해서 바로 브라우저에서 열거나, 간단한 file:// URL로 접근하는 경우가 이에 해당한다.

이런 상황에서는 import 문을 이용해 JSON 파일을 불러오는 것이 작동하지 않는다. 이는 브라우저의 보안 정책과 관련된 문제, 또는 모듈 시스템 자체가 지원되지 않는 환경이 있을 수 있기 때문이다.

대신에 fetch API나 AJAX와 같은 방법을 사용해야 JSON 데이터를 불러올 수 있다. 이런 방법들은 브라우저에서 동적으로 데이터를 불러오는 방법이며, 별도의 설정이나 빌드 과정 없이도 작동한다.

하지만 매번 fetch나 AJAX를 사용하기에는 번거롭고 불편하다.

맞다, fetch나 AJAX를 사용하는 것은 간단한 설정 없이도 브라우저에서 동작하긴 하지만, 매번 이런 식으로 데이터를 불러오기에는 코드가 반복되거나 관리가 어려울 수 있다.

이런 경우에 유용한 방법은 공통 로직을 하나의 함수나 모듈로 묶어서 재사용하는 것이다. 예를 들어, 공통적으로 JSON 데이터를 불러오는 작업을 하나의 함수로 만들 수 있다.

// fetchData.js
async function fetchData(url) {
  try {
    const response = await fetch(url);
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("데이터를 불러오는 데 실패했다:", error);
  }
}

export default fetchData;

이렇게 하면 다른 자바스크립트 파일에서 이 함수를 불러와 간단하게 사용할 수 있다.

// main.js
import fetchData from './fetchData';

async function main() {
  const messages = await fetchData('path/to/messages.json');
  console.log(messages.hello);
}

main();

이 방법을 사용하면, JSON 데이터를 불러오는 로직이 한 곳에 모여 있어 유지보수가 쉽고, 코드도 깔끔해진다. 이러한 패턴은 자주 사용하는 로직을 모듈화해 재사용성을 높이는 좋은 예시다.

여기서 await을 사용하는 이유는?

await 키워드는 비동기 함수 내에서만 사용할 수 있으며, Promise를 기다려서 그 결과 값을 얻어오는 역할을 한다. await을 사용하면 비동기적으로 처리되는 작업을 마치 동기적인 작업처럼 쉽게 다룰 수 있다.

예를 들어, fetch 함수는 웹에서 데이터를 가져올 때 사용되는 비동기 함수다. fetch를 호출하면 Promise 객체가 반환된다. 이 Promise 객체는 네트워크 작업이 완료되면 결과를 제공한다.

await 없이 fetch를 사용하면 이렇게 작성할 수 있다:

fetch('some/api/endpoint')
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('Error:', error);
  });

이 코드는 작동은 잘 하지만, 연속적인 비동기 작업을 다룰 때는 콜백 함수가 많아져서 코드가 복잡해질 수 있다. 이를 콜백 지옥(Callback Hell)이라고도 부른다.

await을 사용하면 이런 문제를 간단하게 해결할 수 있다. 예를 들면:

async function fetchData() {
  try {
    const response = await fetch('some/api/endpoint');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error:', error);
  }
}

이 코드는 위의 코드와 동일한 작업을 수행하지만, 훨씬 더 읽기 쉽고 이해하기 쉽다. 이렇게 await을 사용하면 비동기 작업을 동기적으로 처리하는 것처럼 코드를 작성할 수 있어 코드의 가독성과 유지보수성이 높아진다.

그렇다면 user string을 js에 저장해서 사용하는 것과 json에 저장해서 사용하는 것에 대해서 성능적인 장단점은 어떤가?

JS 파일에 저장

장점:

  1. 직접적인 접근: JS 파일에 문자열을 저장해두면, 해당 문자열을 직접 변수나 상수로 접근할 수 있다. 이는 코드 내에서 즉시 사용이 가능하다는 장점이 있다.
  2. 로직 적용 용이: 필요한 경우 문자열을 동적으로 생성하거나 함수를 사용해 문자열을 처리할 수 있다.

단점:

  1. 보안 문제: JS 파일은 클라이언트에서 직접 접근 가능하므로, 중요한 문자열을 저장하기에는 부적절하다.
  2. 다국어 지원 복잡성: 다양한 언어의 문자열을 동적으로 로드하기 어려워, 다국어 지원 구현이 복잡해질 수 있다.

JSON 파일에 저장

장점:

  1. 데이터 구조 명확성: JSON 형식이므로, 데이터의 구조가 명확하다. 이로 인해 다국어 지원이나 대량의 데이터 관리가 편리하다.
  2. 재사용성: JSON 파일은 다른 시스템과의 데이터 교환에도 자주 사용되므로, 재사용성이 높다.
  3. 팀 작업 용이: 개발자 외에도 다른 이해관계자(디자이너, 텍스트 작성자 등)가 쉽게 접근하여 수정할 수 있다.

단점:

  1. 비동기 로딩 필요: 일반적으로 JSON 파일을 읽어오려면 비동기 작업이 필요하다. 이로 인해 초기 로딩 시간이 늘어날 수 있다.
  2. 로직 적용 제한: JSON은 데이터만 저장할 수 있으므로, 동적인 로직을 적용하기 어렵다.

성능적인 측면

  • JS: 브라우저가 JS 파일을 파싱하고 실행하는 과정에서 CPU 리소스를 더 사용할 수 있다. 하지만 이는 대개 미미한 차이다.
  • JSON: 비동기 로딩이 필요하므로 네트워크 지연이 발생할 수 있다. 하지만 캐싱 등의 기술을 사용하면 이 문제를 완화할 수 있다.

결론적으로, 성능 차이는 미미하며, 어떤 형식을 사용할지는 프로젝트의 필요성과 구조에 따라 결정하면 된다.


이렇게 내가 부족한 부분과 의문점들을 생각의 흐름을 따라서 정리를 해보니 더욱 구조화가 잘되고, 추후에 리뷰를 할때도 보다 효율적이라는 생각이 든다. 왜냐하면, 이 내용들을 다 잊어버리게 되더라도 아마도 또 다시 비슷한 의문의 흐름을 타게 되기 때문일 것이다.

댓글 없음:

댓글 쓰기

관련 포스팅