TIL

오늘 한 일

1. 프론트엔드 개발 과정 - 리액트 실습

수업시간 대부분이 실습 시간이었는데 덕분에 조금 리액트 state와 props, Component같은 기본 사용법은 익숙해지는 것 같다. 빨리 숙지해서 Redux같은 심화 부분을 들을때 어려움이 없도록 많이 연습해야겠다.

2. Algorithm 문제 풀이

저번 풀이는 연결 리스트에 대해 이해가 없어서 오래 걸렸다. 몇번 실행 오류 나보면서 이해하게 되었지만, 나중에 따로 정리해봐야겠다. 다른 식으로 풀어봤는데, 다행히도 저번에 푼 것보다는 효율적인 코드인 것 같다. 시간이 단축되었다. 다른 방법 딱 한번만 더 생각해보고 다른 사람 풀이 보면서 포스팅을 다시 추가해야겠다.

앞으로 할 일

  • React 캘린더 완성하기
  • RGB 챌린지 React로 구현해보기
  • 알고리즘 Add Two Numbers 다시 풀어보고 다른 사람 풀이 정리하기(데이터 구조 - 연결리스트 정리하자)
Share Comments

leetcode - Reverse Integer

leetcode 문제링크

Given a 32-bit signed integer, reverse digits of an integer.

  • Example 1:
    • Input: 123
    • Output: 321
  • Example 2:
    • Input: -123
    • Output: -321
  • Example 3:
    • Input: 120
    • Output: 21

Note:
Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

나의 풀이

1
2
3
4
5
6
// Runtime: 80 ms
var reverse = function(x) {
const range = 2 ** 31;
const result = parseInt(x.toString().split('').reverse().join(''));
return (result > (range - 1)) ? 0 : x >= 0 ? result : result * -1;
};

코드가 짧아보인다고 빠른게 아닌 것임을…
Big O Notation을 아직 제대로 이해하지 못했지만 제아무리 코드상 짧아보여도 반드시 좋은 코드인 것은 아니란 걸 알았다.(그리고 나의 코드가 그런듯…)

range = 2 ** 31Math.pow(2, 31)로 구해도 될 것 같고 숫자를 문자열 화하는 방법은 다양하다. ('' + x, ${x}, x.toString()…)

문제 자체가 풀기에는(정말 푼 것에만 의미를 두자면) 크게 어렵지 않았고, 나는 숫자를 reverse한다고 해서 당연히 1문자열로 만들어서, 2배열화해서, 3reverse메소드로 뒤집고 다시 4join메소드로 합쳐준 다음 5숫자화하면 되는 것 아닌가?라고 생각했다.
그리고 이게 거의 공식처럼 머릿속에 있었는데, 다른 사람들 풀이를 보니까 생각이 넓어지는 기분이다.

다른 사람 풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 64ms
var reverse = function(x) {
var isNeg = x < 0;
var result = 0;

x = Math.abs(x);

while(x) {
var lastDigit = x % 10; // 33 % 10 = 3
result *= 10; // 0
result += lastDigit; // 3
x = parseInt(x / 10); // 3
}

result = isNeg ? -result : result;

if(result > Math.pow(2, 31) - 1 || result < -Math.pow(2, 31)) {
return 0;
}

return result;
};

이 풀이는

  1. 먼저 음수인지 여부를 저장해둔다.
  2. x를 Math.abs()를 통해 절대값으로 만든다.
  3. 만약 그 전에 result에 저장된 값이 있으면 10을 곱해줘서 자리수를 올린다.
  4. x를 10으로 나눈 나머지를 result에 더해준다.
  5. x에는 다시 10으로 나눈 정수값만 저장하면서 x가 0이 될때까지 반복한다.
  6. 이렇게 reverse한 수가 음수인지 여부에 따라 다시 음수화시켜주고
  7. 만약 제한범위를 넘어서면([−231, 231 − 1]) 0을 반환하고 아니면 result를 그대로 반환한다.

위의 풀이와 비슷한데 조금 다른 풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 68ms
var reverse = function(x) {
var MAX = Math.pow(2, 31) - 1;
var number = 0,
symbol = 1;

if(x < 0){
x = Math.abs(x);
symbol = -1;
}

while(x > 0){
number = number * 10 + x % 10;
x = Math.floor(x / 10);
}

return number > MAX ? 0 : symbol * number;
};

1
2
3
4
5
6
7
8
9
10
11
// 76ms
const reverse = function(x) {
if (x==0) return 0
let isPositive = x > 0

let digits = (isPositive)? x.toString().split("").reverse()
: (-x).toString().split("").reverse()
let num = parseInt(digits.join(''), 10)
if (num >= 2147483647) return 0
return num * (isPositive? 1: -1)
};

이 풀이는 나의 경우 Math.pow(2, 31)내지는 2 ** 31로 구하도록 했는데 이미 구해진 값을 넣어서 연산을 하나 줄였다.

대체로 while문을 통해서 10을 이용한 연산을 통해 자리수를 바꿔주는 방법이 문자열 → 배열 → reverse로 하는 방법보다 빠른 것 같다.

Share Comments

자바스크립트 모듈

패스트 캠퍼스 프론트엔드 개발 스쿨에서 배운 내용을 정리합니다.
내용에 오류가 있다면 댓글 남겨주시기 바랍니다.

모듈

큰 규모의 프로젝트에서 JavaScript 코드를 여러 파일과 폴더에 나누어 작성하고, 충돌하지 않게 서로가 서로를 효율적으로 불러올 수 있도록 해주는 시스템이 필요해졌다.

ES2015 모듈: script태그에 type="module" 어트리뷰트 추가

1
2
<!-- 모듈로서 동작한다, 파일 확장자는 대개 .mjs -->
<script type="module" src="index.mjs"></script>

단, 다음과 같은 이유로 아직 브라우저에 내장된 모듈 기능을 사용하는 경우가 별로 없다.

  • 이전까지의 JavaScript 파일의 동작방식과 다른 동작방식을 가지고 있다.
  • 모듈이 제대로 동작하기 위해 몇가지 조건을 충족시켜야 한다.
  • 구형 브라우저는 모듈을 지원하지 않는다.

대신 Webpack, Parcel 등의 모듈번들러를 통해 변환과정을 거친 뒤, 브라우저에서 일반적인 JavaScript파일로 불러오는 방법이 널리 사용되고 있는 추세이다.

모듈 번들러는 여러 자바스크립트 파일을 설정에 따라 하나 이상의 파일로 합쳐주는 프로그램이다. 최신문법을 트랜스파일링 해주는 기능까지 갖추고 있다.

모듈 번들러들은 파일간 관계를(의존성) 분석해서 모듈을 하나로 합쳐줄 때 사용하는 방식이 각자 다르다.

  • Webpack은 import를 통해 분석한다.
  • Parcel은 html 태그를 보고도 분석한다.(html 안에 link태그 쓰고, scss를 불러오는 식으로 쓸 수 있다.)

1. 모듈이란?

ES2015 모듈: JavaScript코드를 담고 있는 파일

  • import 혹은 export구문을 사용할 수 있다.
  • 기본으로 엄격모드로 동작한다.
  • 모듈 파일의 가장 바깥쪽에서 선언된 이름은 전역 스코프가 아니라 모듈 스코프에서 선언된다.

2. 모듈 스코프

1
2
3
4
5
// variables.js
var foo = 'bar';

// 이 파일이 모듈로서 사용되고 있다면, `undefined`가 출력된다.
console.log(window.foo);

이 모듈스코프는 모듈 파일마다 개별적으로 존재한다.

따라서 여러 모듈의 가장 바깥쪽에서 같은 이름으로 변수, 함수, 클래스를 선언하더라도,
서로 다른 스코프에서 선언되기 때문에 이름의 충돌이 생길 일이 없다.

3. export & import

값이 아니라 이름이 export되는 것

  • 모듈 스코프에서 정의된 이름은 export 구문을 통해 다른 파일에서 사용할 수 있다.

    • variables.js

      1
      2
      3
      4
      const foo = 'bar';
      const spam = 'eggs';

      export {foo, spam};
    • functions.js

      1
      2
      3
      4
      5
      import {foo, spam} from './variables.js';

      console.log(foo);
      console.log(spam);
      `
  • 함수나 클래스도 export를 통해 여러 모듈에서 재사용할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    function add(x, y) {
    return x + y;
    }
    class Person {
    // ...
    }

    export { add, Person };
  • 다른 모듈에 있는 이름을 사용하려면, 반드시 모듈에서 이름을 export 해주어야 한다.
    모듈 실행환경에 따라 에러나, 이름에 undefined가 들어가는 식으로 의도치 않게 동작한다.

4. 선언과 동시에 export 하기

이름을 선언하는 구문 앞에 export를 붙여주면, 선언과 export를 한꺼번에 할 수 있다.

1
2
3
4
5
6
7
export const foo = 'bar';
export function add(x, y) {
return x + y;
}
export class Person {
// ...
}

5. default export

모듈을 대표하는 하나의 을 지정하고, 그 값을 다른 모듈에서 편하게 불러와서 사용할 수 있다.
이렇게 사용하는 값을 default export라고 부른다.

  • foo.js

    1
    export default 'bar';
  • main.js

    1
    2
    3
    4
    // 중괄호를 생략하면, 모듈의 default export를 가져온다.
    import foo from './foo.js'

    console.log(foo); // bar

※ 모듈당 하나의 default export밖에 허용되지 않는다.
모듈에는 하나의 default export와 여러개의 named export(일반적인 export)를 지정할 수 있다.

import 구문에서 default export와 일반적인 export를 동시에 가져올 수 있다.

1
2
                        // node_modules에 설치된 것은 따로 path없이 불러오면 됨
import React, {Component, Fragament} from 'react';

1
2
3
export default class React {}
export class Componet { /*...*/ }
export class Fragment { /*...*/ }

6. 다름 이름으로 export & import 하기

export혹은 import 하는 이름의 뒤에 as를 붙여 다른 이름이 대신 사용되게 할 수 있다.

  • export 이름 뒤에 as

    • foo.js

      1
      2
      const foo = 'bar';
      export {foo as FOO};
    • main.js

      1
      import {FOO} from './foo.js'
  • import 이름 뒤에 as

    • foo.js

      1
      2
      const foo = 'bar';
      export foo;
    • main.js

      1
      2
      import {foo as FOO} from './foo.js'
      console.log(FOO)

7. 모듈 사용 시 주의할 점

모듈 번들러는 import를 하지 않으면 아예 JavaScript코드를 실행시키지 않는다.
모듈간의 의존관계를 다 파악한 뒤 필요한 것만 실행시킨다.

log.js

1
2
console.log('log~~~~~')
export const foo = bar;

main.js

1
2
3
import {foo} from './log'

// log~~~~가 콘솔에 출력된다.

만약 다른 모듈에서도 ‘log.js’를 import 하더라도 ‘log~~~~’는 한번만 출력된다.
이는 import구문이 코드를 실행시키라는 명령이 아니기 때문이다.
exportimport 구문은 단지 모듈간의 의존관계를 나타내는 것일 뿐이다.

ECMAScript 공식 명세에는 모듈을 불러오는 방법에 대한 내용이 포함되어 있지 않다.
모듈번들러, 브라우저마다 모듈을 불러오는 방법이나 구체적인 동작 방식은 다를 수 있다.

8. ES2015 이전의 모듈들

ES2015 모듈 이전에 CommonJS, AMD 등의 모듈 시스템이 있었다.

1
2
3
4
5
6
// Node.js에서 쓰는 모듈 객체
const os = require('os')
module.export = {
a: a
b: b
}
Share Comments

try...catch, 자바스크립트에서의 예외 처리

패스트 캠퍼스 프론트엔드 개발 스쿨에서 배운 내용을 정리합니다.
내용에 오류가 있다면 댓글 남겨주시기 바랍니다.

예외처리

프로그램의 언어들이 항상 완벽하게 동작하지는 않는다.
단순 버그이거나, 프로그래머가 잘못 작성했거나, 프로그래밍 언어 자체가 에러를 내는 경우가 있다.

1. 동기식 코드에서의 예외 처리

프론트엔드 개발자의 실수

1
new Array(-1) // RangeError: Invalid array length

1
console.log(foo) // ReferenceError: foo is not defined

프론트엔드 개발자의 의도와 다른 실수

1
2
fetch('https://nonexistent-domain.nowhere'); // TypeError: Failed to fetch
// 위 주소는 맞는데 서버/네트워크 쪽 에러가 있다거나

에러가 발생하면 나머지 로직이 실행되지 않는다. 그 시점에 실행 중이었던 작업을 완료할 수 없게 된다.

1
2
3
console.log('에러가 나기 직전까지의 코드는 잘 실행됩니다.');
new Array(-1); // RangeError: Invalid array length
console.log('에러가 난 이후의 코드는 실행되지 않습니다.'); // 이것은 실행되지 않는다.

위와 같이 코드의 실행이 중단된다.

try...catch...finally 구문을 사용하면 에러가 나더라도 코드의 실행을 지속할 수 있다.

1
2
3
4
5
6
7
8
9
10
try {
// 여기서 에러가 나면 에러가 난 시점에 코드의 흐름이
// catch로 넘어간다.
console.log('에러가 나기 직전까지의 코드는 잘 실행됩니다.');
new Array(-1); // RangeError: Invalid array length
console.log('에러가 난 이후의 코드는 실행되지 않습니다.');
} catch (e) {
console.log('코드의 실행 흐름이 catch 블록으로 옮겨집니다.');
alert(`다음과 같은 에러가 발생했습니다: ${e.name}: ${e.message}`);
}
  • try: 에러가 났을 때 원상복구를 시도할 코드. 에러 발생시 코드의 실행 흐름이 catch 블록으로 옮겨간다.
  • catch: 에러에 대한 정보를 담고 있는 객체(위 예제의 e)를 사용할 수 있다.

    • e.name: RangeError같은 에러의 이름
    • e.meassage: Invalid array length 에러 메시지
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      try {
      console.log('에러가 나기 직전까지의 코드는 잘 실행됩니다.');
      /* new Array(-1); */
      console.log(foo);
      console.log('에러가 난 이후의 코드는 실행되지 않습니다.');
      } catch (e) {
      if(e.name === 'RangeError') {
      alert(`배열 생성자에 잘못된 인수가 입력되었습니다.`)
      } else if (e.name === `ReferenceError`) {
      alert(`선언되지 않은 변수가 사용되고 있습니다.`)
      }
      console.log('코드의 실행 흐름이 catch 블록으로 옮겨집니다.');
      }
  • finally: try블록 안에서의 에러 발생 여부와 관계 없이 무조건 실행되어야 하는 코드
    return, break, continue등으로 코드의 실행 흐름이 즉시 이동되더라도 실행된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for (let i of [1, 2, 3]) {
    try {
    if (i === 3) {
    break;
    }
    } finally {
    console.log(`현재 i의 값: ${i}`);
    }
    }
    • finally블록은 catch 블록과도 같이 사용된다.
      • 에러가 안 났을 때: try - finally
      • 에러가 났을 때: try - 에러발생 - catch - finally

1-1. 직접 에러 발생시키기

코드를 다른 사람이나 미래의 내가 의도한 대로 사용하지 않을 경우 에러가 발생하도록 할 수 있다.

Error생성자, throw구문

1
2
3
4
5
6
const even = parseInt(prompt('짝수를 입력하세요'));
if (even % 2 !== 0) {
throw new Error('짝수가 아닙니다.');
}
// 3을 입력할 경우
// Error: 짝수가 아닙니다.

1
2
3
4
5
6
7
8
9
throw 'ggg';
// 던지는 것에 제한이 없으나
throw new Error('ddd')
// 반드시 에러 객체를 던져야 한다.

const e = new Error('짝수가 아니다')
// Error는 어디서나 쓸 수 있는 객체(생성자)이다.
e;
// Error: 짝수가 아니다.

다음과 같이 내가 에러를 만들어 던질 수 있고, 이를 try...catch 구문으로 잡을 수 있다.

1
2
3
4
5
6
7
8
try {
const even = parseInt(prompt('짝수를 입력하세요'));
if (even % 2 !== 0) {
throw new Error('짝수가 아닙니다.');
}
} catch (e) {
alert(e.message);
}

복잡한 프로그램을 짜다보면 추가적인 자세한 정보를 추가해서 에러를 만들고 싶게 된다.
에러의 종류를 구분해야 하거나 에러 객체에 기능을 추가해야 할 필요가 있다.

그냥 내장 에러 생성자가 아니라 내가 자체 Error 클래스를 만들경우 다음과 같은 방법이 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyError extends Error {
constructor(value, ...params) {
super(...params);
this.value = value;
this.name = 'MyError';
}
}

try {
const even = parseInt(prompt('짝수를 입력하세요'));
if (even % 2 !== 0) {
throw new MyError(even, '짝수가 아닙니다.');
}
} catch (e) {
if (e instanceof MyError) {
console.log(`${e.name}: ${e.value}${e.message}`);
}
}

에러에서도 동기식 처리와 비동기식 처리가 있다.

2. 비동기식 코드에서의 예외 처리

2-1. 비동기 콜백

비동기식으로 작동하는 콜백의 내부에서 발생한 에러는, 콜백 바깥에 있는 try 블록으로는 잡아낼 수 없다.

1
2
3
4
5
6
7
8
9
10
try {
setTimeout(() => {
// 비동기 코드 안의 에러는 잡히지 않는다.
throw new Error('에러!');
});
} catch (e) {
console.error(e);
}
// Uncaught Error: 에러!
// 에러가 잡히지 않아서 생기는 에러;;

JavaScript 엔진은 에러가 발생하는 순간 호출 스택을 되감는 과정을 거친다.
이 과정 중에 try 블록을 만나야 코드의 실행 흐름을 원상복구시킬 수 있다.

에러는 호출스택과 관련되어 있다.

아래는 동기식 예외 발생

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function add(x, y) {
// 에러를 이곳에서 발생시키고
new Array(-1);
return x + y;
}

function add2(x) {
return add(x, 2);
}

function add2AndPrint(x) {
// try... catch 구문이 여기있지만
// 자바스크립트 실행 엔진이 에러가 발생하면 호출 스택을 하나씩 지워가면서
// try가 있는지 찾아본다.
try {
// 여기서 add2를 호출하고 add2는 add를 호출하기 때문에 에러가 잡힌다.
const result = add2(x);
console.log(result);
} catch(e) {
alert('잡았다!');
}
}

add2AndPrint(3); // alert으로 '잡았다!'가 뜬다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function add(x, y) {
// 에러를 이곳에서 발생시키고
new Array(-1);
return x + y;
}

function add2(x) {
// 호출스택을 되감다 가장 먼저 만나는 try에서 에러가 잡힌다.
try {
return add(x, 2);
} catch(e) {
alert('add2에서 잡히나?')
}
}

function add2AndPrint(x) {
try {
const result = add2(x);
console.log(result);
} catch(e) {
alert('잡았다!');
}
}

add2AndPrint(3); // alert으로 'add2에서 잡히나?'가 뜬다.

비동기 콜백이라면 단순 try...catch 구문으로는 잡을 수 없다.
비동기 콜백이 실행될 때는 이미 호출스택이 비워져 try를 찾을 수 없다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function add(x, y) {
setTimeout(() => {
// 이 콜백이 일단 태스크큐에 들어갔다가 호출 스택이 비워지면 실행된다.
// 호출스택을 되감아 가면서 try를 찾아야하는데
// 이 콜백이 실행될 때는 이미 호출스택이 비워졌으므로 try를 찾을 수 없다.
new Array(-1);
})
return x + y;
}

function add2(x) {
try {
return add(x, 2);
} catch(e) {
alert('add2에서 잡히나?')
}
}

function add2AndPrint(x) {
try {
const result = add2(x);
console.log(result);
} catch(e) {
alert('잡았다!');
}
}

add2AndPrint(3);

따라서, 비동기 콜백 내부에 try를 작성해주어야 한다.

이벤트 리스너와 try catch 블록 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const buttonEl = document.querySelector('button');

try {
buttonEl.addEventListener('click', e => {
try {
new Array(-1);
alert('버튼이 눌렸습니다.');
} catch (e) {
alert('이벤트 리스너 안에서 에러가 발생했습니다.');
}
})
} catch (e) {
alert('에러가 발생했습니다.'); // 출력되지 않음
}

2-2. Pomise

Promise 객체는 세 가지 상태를 가질 수 있다.

  • pending - Promise 객체에 결과값이 채워지지 않은 상태
  • fulfilled - Promise 객체에 결과값이 채워진 상태(이때 then메소드 또는 await를 통해 무언가를 실행했다.)
  • rejected - Promise 객체에 결과값을 채우려고 시도하다가 에러가 난 상태
    • then메소드에 첫 번째 인수로 넘겨준 콜백이 실행되지 않고, 두 번째 인수로 넘겨준 콜백이 실행된다. 그리고 이 콜백에는 에러 객체가 첫번째 인수로 주어진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const p = new Promise(resolve => {
const even = parseInt(prompt('짝수를 입력하세요'));
if (even % 2 !== 0) {
throw new Error('짝수가 아닙니다.');
} else {
// 짝수면 fullfiled되어 then메소드의 첫번째 인수로 들어간 함수가 실행
resolve(even);
}
});

// then 콜백에서 반환된 값이 다음Promise의 값이 된다.
p.then(even => {
return '짝수입니다.';
}, e => {
return e.message;
}).then(alert);
// .then(msg => alert(msg))와 같음

Promise가 rejected 상태가 되었을 때 catch 메소드를 통해 다음과 같은 방법으로도 에러 처리 콜백을 지정해 줄 수 있다.

1
2
3
4
5
p.then(even => {
return '짝수입니다.';
}).catch(e => {
return e.message;
}).then(alert);

2-3. 비동기 함수

비동기 코드에서의 try...catch와 비동기 함수에서의 try...catch는 다르게 동작한다. (내부 동작 방식이 완전히 다르다. - 비동기 함수를 사용하면 예외처리도 보다 편하게 할 수 있다.)

비동기 함수 내부에서는, rejected 상태가 된 Promise객체를 동기식 예외처리 방식과 동일하게 try...catch...finally 구문으로 처리할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
async function func() {
try {
// ※ 단, Promise 객체에 대해 await 구문을 사용해야만
// 에러가 발생했을 때 catch 블록으로 코드의 실행 흐름이 이동한다.
const res = await fetch('https://nonexistent-domain.nowhere');
} catch (e) {
console.log(e.message);
}
}

func(); // 출력 결과: Failed to fetch

Share Comments

TIL 20180611

오늘 한 일

1. 프론트엔드 개발 스쿨 과정

오늘은 예외 처리(try...catch)와 모듈부분 진도를 나가고 리액트 실습(todoList)을 했다.

예외 처리 부분은 중간프로젝트 하면서 미리 읽어봤었는데, 호출스택과 태스크 큐에서의 코드 동작원리까지 같이 설명해주시니 좀 더 깊이있게 이해되는 것 같다.

리액트 컴포넌트 간의 변경사항 공유 때문에 조상 컴포넌트에서 상태를 관리하니까 컴포넌트를 나눌때마다 상태도 내려보내줘야해서 헷갈린다.
아직까지 배운 내용에서는 내가 중간 프로젝트때 가장 하위의 template에 여러 정보를 담은 객체를 상위 template으로부터 내려보내느라 그 사이의 하위 template에도 똑같이 그 객체를 내려보내줬던 방식과 크게 다르지 않은 것 같다.
Redux나 Context를 통해서 이런 부분을 효율적으로 관리할 수 있다는데, 어떤식으로 만들었길래 그게 가능할까 신기하다.

강사님과 실습 시간에 어떤 메소드는 하위 컴포넌트에서 작성하고 어떤 메소드는 상태를 관리하고 있는 App 컴포넌트에 작성했다. 그러면서 역할과 책임에 대한 말씀을 해주셨다.
역할과 책임을 어떻게 정해야할지는 프로젝트를 진행할때마다 어렵게 느껴진다. 정답이 있는 건 아닌것 같은데 어떻게 코드를 짜야 역할과 책임에 맞게 코드를 작성하게 되는 건지 아직은 감이 잡히지 않아서 많이 만들어봐야겠다.

2. Algorithm 문제 풀이

다른 사람들 풀이를 보니까 숫자를 거꾸로 만드는 방법에 대해서 다른 방법을 알게 되었다. 어제 풀었지만 차마 포스팅할 수 없는 부끄러운 풀이라 좀 더 다듬으면 포스팅하자고 미뤄둔 문제도 숫자를 문자열화하는 식으로 풀었는데, 이번 문제를 좀 더 응용하면 새로운 방식으로 풀 수 있을 것 같다.

3. React 캘린더 만들기

moment.js를 사용하고 있는데, 캘린더의 body 부분의 표를 짜는 것만 구하면 수월할 것 같은데, 아직 못 만들었다. 하지만 어젯밤에 자기 전에 생각해본 것을 좀 더 수정해보면 될 것 같다.

앞으로 할 일

  • React 캘린더 완성하기
  • JSX 공부하기
Share Comments

TIL 20180610

오늘 한 일

1. 리액트 캘린더 프로젝트

리액트 연습삼아 리액트로 jQuery의 Datepicker같은 캘린더를 만들고 있다.
연습으로 만들어보는 건데 나에게 좀 어려운 것 같다. 리액트 문서도 다시 찾아보면서 하고 있다. 생각보다 한 것이 없는데 하루가 금방 지나가버려서 마음이 조급해진다. 좀더 시간을 잘 쪼개서 써야겠다.

앞으로 할 일

  • React 캘린더 완성하기
Share Comments

TIL 20180609

오늘 한 일

1. hexo로 블로그를 만들었다.

금요일, 소프트웨어 공학 특강시간에 최우영 강사님이 보여주신 초보몽키의 개발공부로그라는 블로그에 감명받아 당장 블로그를 만들었다. 사실 그전에도 알고리즘 퀴즈 관련해서 구글에서 검색하면 거의 매번 보이던 블로그였는데, 학원 수강생이었다는 거에 충격이랄지 나도 저렇게 열심히 살아야겠다는 자극을 받았다.

hexo + icarus 테마 + github page로 블로그를 만들었다.
어느정도 파악해보려고 열어봤더니 EJS와 Stylus의 조합이라 당황스러웠다.
처음에는 체감상 Jekyll보다 어렵게 느껴졌는데(Jekyll 테마는 Sass였다.) 보다보니 익숙해지는 것 같다. 스타일은 아직 수정한 것이 없는데, 테마 자체의 디자인도 마음에 들지만 천천히 바꿔봐야겠다.
예를들면 모바일에서는 헤더를 상단에 픽스시킨다든지 정도의 커스터마이징은 필요해보인다.

만드는 것도 파악하는 것도 오래 걸려서, 저번 Jekyll 블로그처럼 학원 과정 끝나고 시간이 남으면 만들까 생각도 했는데, 일단 만들어놓고 천천히 바꾸자는 생각으로 만들었더니 하길 잘했다는 생각이 든다. github와 다르게 좀 더 글이 정제되어 보인다.

프로필 일러스트도 하는김에 만들었다.(이놈의 디자인 욕심…) 마침 github가 로키(턱시도 고양이)여서 로키 일러스트를 만들었다. 생각보다 금방 구상하고 오랜만에 일러 만지느라 헤맨 것 치고는 시간도 얼마 소요되지 않았다.(다행이다. 오래걸렸으면 자괴감이 들었을지도…)

지난 TIL과 알고리즘 풀이는 블로그로 옮길지, 아니면 기존 github 레포지토리로 남길지는 생각해봐야겠다.

2. 스캐폴딩, 퍼머링크 등 모르는 용어를 정리했다.

hexo로 블로그를 만들려다 보니 모르는 용어가 많았다.
스캐폴딩, CRUD, 퍼머링크를 정리하는 것으로 첫 포스팅을 하기로 했다. 대부분 데이터베이스나 서버 개발 쪽 아니면 아키텍처 관련 용어인듯하다. 데이터베이스 쪽도 생활코딩같은 강의를 통해서 틈틈이 공부해야겠다. 모르는 용어가 점점 줄어들었으면 좋겠다. (하지만 또 새로운 게 생겨나겠지…)

앞으로 할 일

  • React로 간단한 미니 프로젝트 만들기(학원내 스터디)
  • JSX 공부하기

모르는 게 많으니까 해야겠다 하는 것도 점점 많아진다. 그리고 알면 알수록 부족함이 보여서 더더욱 심해지는 것 같다. 이럴때일수록 무엇을 먼저 할지 우선 순위를 빠르게 정하고 밀고 나가야겠다.

블로그 만들면서 오랜만에 나를 프론트엔드 개발의 길로 이끈 블로그에 들어갔다. HyunSeob이라는 분의 블로그인데, hexo로 만들었다는 포스팅을 봤던 기억이 나서 다시 찾아봤다. (오랜만에 읽어보다 이 마음에 드는 테마도 건졌다.)
그 당시 gulp로 Sass를 써보다가 Webpack을 사용해보자면서 검색하다 보게 된 블로그였다. 포스팅이 엄청 많은 것은 아니지만, 1년 안에 포스팅한 내용이 Node.js, Webpack, AngularJS, CoffeScript, TypeScript등이어서 적잖게 충격을 받았다.
이렇게 열심히 트랜드를 쫓아가는구나, 나도 머물러 있으면 안 되겠다는 자극을 받았다.

그때의 마음을 항상 잊지 않으려한다. 지치지 않고 계속 달릴 수 있으면 좋겠다.

Share Comments

스캐폴딩, CRUD, 퍼머링크

hexo로 블로그 만들면서 모르는 용어를 정리했다.

1. 스캐폴딩(scaffolding)

건축용어로 비계라는 의미인데, 작업을 위해 임시로 설치한 가설 발판이나 가설 구조물을 말한다.
프로그래밍 쪽에서는 데이터베이스의 각 테이블에 대한 웹 페이지를 자동으로 생성하는 Dynamic Data 요소를 말한다.

이렇게 자동 생성된 웹 페이지를 통해 각 테이블에 대해 만들기, 읽기, 업데이트 및 삭제(CRUD) 작업을 수행할 수 있다. 스캐폴딩을 구성하는 템플릿을 사용해 효율적인 데이터 기반 웹 사이트를 신속하게 작성할 수 있다.
개발 중인 코드가 제 모습을 가지기 전까지 임시 스캐폴딩 코드를 코드 구조를 잡는데 사용한다고 한다.

정리하면 웹 개발 프레임워크(ASP.NET이나 Ruby on Rails등)에서 단순한 CRUD 서비스 프로세스를 구축하도록 지원하는 템플릿 개념인 것 같다.

참고

2. CRUD

Create, Read, Update, Delete
대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능을 묶어서 일컫는 말.
사용자 인터페이스가 갖추어야 할 기능(정보의 참조/검색/갱신)을 가리키는 용어로서도 사용된다.

참고

인터넷에서 특정 페이지에 영구적으로 할당된 URL 주소를 뜻한다.
영구적인 주소라는 뜻인데 한국에서는 고유 링크, 고유 주소라는 명칭으로 광범위하게 퍼져있다.

퍼머링크를 사용하는 대표적인 사례는 블로그.
시간이 지남에 따라 새로운 내용이 추가되면서 블로그 글의 위치가 쉽게 변하므로, 각각의 글에 영원히 고정된 주소를 제공하는 것이라고 위키백과에 정의되어 있다.

hexo에서는 _config.yml 파일이나 font-matter(파일 시작 시 작성하는 YAML, JSON 구역 - 게시물에 대한 환경설정을 하는 곳)에 각 포스트의 permalink의 형식을 지정할 수 있게 한다.

hexo 설치시 처음 _config.yml에는 아래와 같이 되어있는데

1
permalink: :year/:month/:day/:title/

결과는 2018/06/09/hello-world로 나온다.

참고

Share Comments