React 개요


지난 시간까지 mongoDB 모델링을 가볍게, 아~주 가볍게 살펴보았다.

그리고 몇차례에 걸쳐 수정했으나 여전히 변경의 여지가 남아있는 찜찜한 상태로 글을 마쳤다.

일단 현 상태로도 정상적으로 기능은 하기에 mongoDB에 대한 깊은 내용은 좀 더 뒤로 미루고

코드가 더 복잡해지기 전에 js쪽 소스들을 React로 conversion 하고자 한다.


최초 Till60 개발에 대한 글을 작성했을 때도 언급했듯이 React 역시 처음 다뤄보는 기술이다.

그런 만큼 우선은 공식 홈페이지에서 개요라도 집고 넘어가야 할 것 같아 우선 오늘은 공식

홈페이지의 메인페이지 내용을 정리해보고자 한다.


1. 기능 목표


기능적으로는 추가 개발 내용이 없다.


2. 기술 목표


기존에 jQuery와 Bootstrap으로 개발된 코드를 React로 conversion.

우선 이번에는 React에 대해 기본 개념을 잡고 다음부터 Sign In, Sign Up 등의 가벼운 화면 작업을

시작하도록 한다.


3. 기술 적용 내용


아래 내용은 React 공식 홈페이지의 메인 페이지 내용을 의역한 것이다.


————————————————————————————————————————————————


1. React는 UI의 상호작용을 보다 쉽게 처리할 수 있는데, 변경된 데이터와 관련된 내용만을 업데이트하고

렌더링 하는 방식으로 이를 효율적으로 수행한다. 이러한 방식은 결국 예측 가능한 코드를 만들 수 있게

하고 따라서 디버깅이 쉬워진다.


2. 자신의 상태를 관리할 수 있는 캡슐화된 컴포넌트를 만듦으로써 복잡한 UI를 쉽게 구성할 수 있으며

이러한 로직을 자바스크립트로 작성하기 때문에 다양한 데이터 형식을 쉽게 전달할 수 있고 또 DOM

에 의존하지 않고 상태를 유지할 수 있다.


3. React는 특정한 기술 스택에 의존하지 않고 React 내에서 새로운 기능들을 개발 할 수 있도록 구현

되었다. 또한 React Native를 이용하면 Node를 이용하여 서버측에 렌더링 하거나 강력한 모바일

앱에 렌더링 하는 것도 가능하다.


————————————————————————————————————————————————


  • 간단한 컴포넌트


React의 기본은 입력 데이터를 전달받아 화면에 표시해주는 render()함수를 구현하는 것이다.

아래 코드는 XML 구문과 유사한 JSX를 이용하여 구현된 코드이다. 하지만 JSX 사용이 필수적인

것은 아니다.


class HelloMessage extends React.Component {

  render() {

    return <div>Hello {this.props.name}</div>;

  }

}


ReactDOM.render(<HelloMessage name="Jane" />, mountNode);

위의 코드에서 눈여겨 봐야 할 것은 HelloMessage라는 클래스 이름과 ReactDOM.render의 호출이다.

ReactDOM.render의 호출을 통해 비로소 화면에 데이터가 출력되는데 이 함수 안에서 HelloMessage

클래스가 어떻게 사용되고 있는지 또 그 안에 name이라는 property가 어떻게 HelloMessage 클래스로

전달되는지(ReactDOM.render 함수의 파라미터에 있는 name은 this.props.name이라는 형태로

HelloMessage 클래스 안으로 전달된다)를 주의해서 보자. 이 코드의 결과는 브라우저 화면에 “Hello Jane”

이라는 문자열을 출력하게 된다.


  • 상태를 갖는 컴포넌트


클래스 내에서 this.props를 이용하여 접근 가능한 입력 데이터 외에도 this.state로 접근 가능한 내부 상태

데이터도 관리할 수 있다. 컴포넌트의 상태가 변경되면 render() 함수를 다시 호출하여 렌더링 된 마크업

문서를 업데이트하게 된다.


class Timer extends React.Component {

  constructor(props) {

    super(props);

    this.state = {secondsElapsed: 0};

  }


  tick() {

    this.setState((prevState) => ({

      secondsElapsed: prevState.secondsElapsed + 1

    }));

  }


  componentDidMount() {

    this.interval = setInterval(() => this.tick(), 1000);

  }


  componentWillUnmount() {

    clearInterval(this.interval);

  }


  render() {

    return (

      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>

    );

  }

}


ReactDOM.render(<Timer />, mountNode);


Component의 lifecycle에 대해서는 추후 자세히 알아보기로 하고 여기서는 간단하게 흐름만 알아보도록 하자


1) 우선 constructor에서 이 컴포넌트의 상태를 나타낼 this.state에 0값으로 설정된 secondsElapsed라는 

    요소를 할당하고 있다.

2) render() 함수가 호출된다.

3) Component의 lifecycle에 의해 componentDidMount가 호출되며 이 안에서 자바스크립트의 setInterval

    함수를 통해 1초에 한 번씩 Timer 클래스에 구현된 tick()함수를 호출한다.

4) tick()함수에서는 이전 상태 값을 파라미터로 전달받아 여기에 1을 더한 후 this.state에 할당된 seconds-

    Elapsed에 값을 새로 설정한다.


이러한 과정을 거쳐서 변경된 this.state만을 새롭게 렌더링하여 화면에 보여주게 된다.


  • Application


props와 state를 이용하여 만든 ToDo Application이다. 이 예제에서는 state를 이용하여 사용자가 입력한

텍스트 뿐만 아니라 항목들의 목록을 추적하여 관리한다. 이러한 과정에서 event handler는 마치 inline으로 

렌더링 되는 것 처럼 보이지만 실제로는 event delegation을 이용하여 수집되고 구현된다.


class TodoApp extends React.Component {

  constructor(props) {

    super(props);

    this.handleChange = this.handleChange.bind(this);

    this.handleSubmit = this.handleSubmit.bind(this);

    this.state = {items: [], text: ''};

  }


  render() {

    return (

      <div>

        <h3>TODO</h3>

        <TodoList items={this.state.items} />

        <form onSubmit={this.handleSubmit}>

          <input onChange={this.handleChange} value={this.state.text} />

          <button>{'Add #' + (this.state.items.length + 1)}</button>

        </form>

      </div>

    );

  }


  handleChange(e) {

    this.setState({text: e.target.value});

  }


  handleSubmit(e) {

    e.preventDefault();

    var newItem = {

      text: this.state.text,

      id: Date.now()

    };

    this.setState((prevState) => ({

      items: prevState.items.concat(newItem),

      text: ''

    }));

  }

}


class TodoList extends React.Component {

  render() {

   return (

      <ul>

       {this.props.items.map(item => (

          <li key={item.id}>{item.text}</li>

        ))}

      </ul>

    );

  }

}


ReactDOM.render(<TodoApp />, mountNode);


앞서 상태를 갖는 컴포넌트에서와 같이 흐름을 살펴보도록 하자.


1) TodoApp 클래스에서는 생성자에서 이벤트를 처리할 두 함수인 handleChange와 handleSubmit을

    this. handleChange와 this. handleSubmit에 할당한다. this.state에는 items라는 배열과 text라는

    문자열로 구성된 object를 할당한다.

2) handleChange 함수는 event 객체를 인자로 전달받아 this.state 중 text에 event target에 입력된

    값을 할당한다.

3) handleSubmit에서는 handleChange에서 this.state에 할당한 text 값과 날짜를 기반으로 한 id

    값을 이용하여 새로운 item을 생성하고 이 item을 this.state의 items 배열에 추가(concat)한 후

    setState 호출로 인해 새로 렌더링이 실행된다.

4) TodoList 클래스는 render 함수만 정의되어있으며 파라미터로 전달받은 item 객체를 이용하여 

    li 리스트를 만든다.


ReactDOM.render 함수가 호출되면 1)에서 초기화가 진행되고 TodoApp 클래스의 render() 함수가

호출되는데 render 함수 내에서는 먼저 this.state 중 items 배열을 파라미터로 하여 TodoList 클래스를

렌더링한다. 즉, 4)의 과정이 실행된다. 이어서 input 폼에는 onChange 이벤트 발생 시  handleChange

함수를 호출한다. 2)의 과정이 실행되는 것이다. input의 value는 최초 상태 또는 item이 등록된 후에는

This.state.text 값이 ‘’로 설정되므로 비어있게 될 것이다. 버튼에는 this.state의 items 배열을 참조하여

현재까지 등록된 item + 1의 수가 표시된다. 마지막으로 Add 버튼을 클릭하면 handleSubmit 함수가

호출되면서 3)의 과정이 진행된다.


  • 컴포넌트에서 외부 플러그인 사용


React는 컴포넌트에서 외부 라이브러리나 프레임워크와 인터페이스 할  때 유연할 뿐만 아니라 hooks를

제공하고 있다. 아래 예제는 Markdown 라이브러리인 remarkable을 이용하여 textarea의 text를

실시간으로 변환하는 예제이다.


class MarkdownEditor extends React.Component {

  constructor(props) {

    super(props);

    this.handleChange = this.handleChange.bind(this);

    this.state = {value: 'Type some *markdown* here!'};

  }


  handleChange() {

    this.setState({value: this.refs.textarea.value});

  }


  getRawMarkup() {

    var md = new Remarkable();

    return { __html: md.render(this.state.value) };

  }


  render() {

    return (

      <div className="MarkdownEditor">

        <h3>Input</h3>

        <textarea

          onChange={this.handleChange}

          ref="textarea"

          defaultValue={this.state.value} />

        <h3>Output</h3>

        <div

          className="content"

          dangerouslySetInnerHTML={this.getRawMarkup()}

        />

      </div>

    );

  }

}


ReactDOM.render(<MarkdownEditor />, mountNode);


마찬가지로 흐름을 살펴보면


1) MarkdownEditor의 생성자에서 handleChange를 bind하고 this.state에는 value라는 키의 문자열

    값을 할당한다.

2) handleChange 함수에서는 textarea의 값을 받아 setState를 통해 상태를 변화시키고 다시 렌더링한다.

3) getRawMarkup 함수에서는 remarkable 라이브러리 객체를 생성하고 this.state.value에 저장된

    문자열을 remarkable 객체를 이용하여 렌더링한 후 리턴한다.

ReactDOM.render가 호출되면 1)의 초기화가 진행되고 render 함수가 호출되면 textarea의 onChange 

이벤트 처리를 통해 내용이 변경될 때마다 handleChange 함수를 호출하고 this.state를 변경한다. 

content라는 클래스명을 가진 div에서는 dangerouslySetInnerHTML을 통해 this.state에 할당된

값을 화면에 출력하는데 이 때 getRawMarkup() 함수를 호출한다. 즉, 3)의 과정을 거친 내용이 화면에

출력된다.


4. 참조 (site 또는 서적)


React 공식 홈페이지 : https://facebook.github.io/react/


5. 확인 사항 (의문 사항)


실제 HTML과 jQuery만으로 구현된 웹 페이지를 React로 conversion하면서 좀 더 심화된

내용 확인이 필요하다.


6. 평가


오늘은 간단히 React 홈페이지의 메인 페이지에 있는 4가지 예제을 살펴보았다. 아직은 그야말로

맛보기 정도에 불과하지만 그래도 대략 감을 잡기에는 부족하지 않은 내용이었다. 앞으로 현재까지

진행된 Till60 홈페이지를 React로 conversion하면서 보다 깊은 내용을 확인해보도록 하겠다.

저작자 표시
신고


mongoDB + Spring Data JPA


지난 시간 간단하게 2개의 Collection으로 구성된 mongoDB의 Document 구조를 설계해 보았다.

하지만 많은 시스템이 그렇듯 한 번에 완결이 되는 그런 개발은 없다. 아무리 작은 개인 프로젝트라도…

물론 가능한한 완벽한 설계를 한다면 그 변경의 폭은 줄어들 수 있겠지만 아마도 계획되지 않은 진행을

완전히 막을 수는 없을 것이다.


오늘은 지난 시간에 이어 Collection 중에 Elements Collection을 조금 변경해볼 것이다.


1. 기능 목표


To-Do 기능의 추가 : 가능한한 단순한 시스템을 만들고자 했으나 목표를 정하고 그 목표를 향해

가는 시스템에서 간단하게나마 계획을 하는 부분을 제외하는 것은 무리인 듯했다. 결국 To-Do

기능을 추가하고 그와 관련하여 예정된 작업과 완료된 작업 간의 상태 이동이나 예정된 작업에서

예정일을 변경하는 기능 그리고 그와 관련된 화면 구현 등의 작업이 진행 될 것이다.


2. 기술 목표


이번까지의 목표는 mongoDB에 대해 조금 더 알아가는 것이다. 이번에는 Document 구조를

바꿔가면서 어떤 구조가 back end나 front end에서 데이터를 다루기가 더 쉬운지를 확인해 볼

것이다. 하지만 mongoDB에 대한 좀 더 심화된 내용은 없을 것이다. 아울러 데이터 처리를 위해

Spring Data JPA의 query method를 사용하는 법을 간단하게 알아볼 것이다.


3. 기술 적용 내용


mongoDB


우선 지난 포스팅에서 설계를 마쳤던 2개의 Collection 중 Profile Collection은 이름을 Profile

AndGoal로 바꾸었고 그 구조적으로는 기본 계정을 제외한 몇개의 항목을 profile이라는 이름의

Sub Document로 만들기로 했다. 우선 지난 시간 만들었던 ProfileAndGoal Collection의

Document 구조를 한 번 보자


ProfileAndGoal Collection


{

    "_id" : ObjectId("584ff54a4fe35068dc44bab4"),

    "_class" : "com.mazdah.tillsixty.account.domain.Profile",

    "name" : "우형준",

    "userId" : "mazdah",

    "password" : "w00hj8928",

    "email" : "woohj70@gmail.com",

    "facebook" : "100000967897658",

    "twitter" : "@mazdah70",

    "link" : "http://mazdah.tistory.com",

    "introduction" : "평범한 아들. 평범한 남자. 평범한 가장. 평범한 개발자. 평범한 서민. 하지만 그 '평범'이 

    너무도 싫은 한 사람",

    "goalList" : [ 

        {

            "goalId" : "584ff54a4fe35068dc44bab4_1",

            "goalTitle" : "Project Master 개발",

            "startDate" : "2016-12-13",

            "endDate" : "2017-12-31",

            "goalDescription" : "관리자와 개발자 모두 쉽게 사용할 수 있는 프로젝트 관리 툴 개발\n

  프로젝트 진행 과정을 쉽게 시각화 문서화하여 진행 상태를 직관적으로\n

  확인할 수 있도록 개발",

           "goalStatus" : "O",

           "createDate" : "2016-12-13"

        }

    ]

}


위 Document 중 email, facebook, twitter, link, imgPath, introduction 등 6개의 항목을 

Sub Document로 만들기로 하여 다음과 같은 구조로 변경하였다.


{

    "_id" : ObjectId("587e18514216afd4103453c2"),

    "_class" : "com.mazdah.tillsixty.account.domain.User",

    "name" : "우형준",

    "userId" : "mazdah",

    "password" : "w00hj8928",

    "profile" : {

        "facebook" : "100000967897658",

        "twitter" : "@mazdah",

        "link" : "http://mazdah.tistory.com",

        "introduction" : "평범한 아들. \n평범한 남자. \n평범한 가장. \n평범한 개발자. \N

    평범한 서민. \n하지만 그 '평범'이 너무도 싫은 한 사람"

    },

    "goalList" : [ 

        {

            "goalId" : "587e18514216afd4103453c2_1",

            "goalTitle" : "AI 전문가 되기",

            "startDate" : "2017-01-17",

            "endDate" : "2017-12-31",

            "goalDescription" : "TensorFolw를 시작으로 머신 러닝과 딥 러닝을 학습하여 인공 지능 

  분야의\n전문가가 될 수 있도록 함",

            "goalStatus" : "O",

            "createDate" : "2017-01-17"

        }

    ]

}


사실 사용자 계정과 Profile 정보는 명백하게 1:1의 관계이고 크게 변동이 있을만한 정보들이

아니기 때문에 굳이 Sub Document로 만들이 않아도 되었을 것이다. 하지만 분명 기본 

계정 정보와는 성격이 다른 정보들이고 추후 항목이 추가될 수도 있으며 RDBMS로의 전환을

고려한다면 일단 구조적으로도 분리시켜 놓는 것이 좋을 것이라는 판단이다.


정작 많은 고려를 해야 하는 것은 Elements쪽이었다. To-Do 기능을 추가함에 따라 하나의

Element가 상태가 변할 수도 있고 그에 따라 몇몇 정보도 같이 변화하기 때문에 이에 맞는

구조를 찾아야 하는 것이다. 그리고 그 과정에서 mongoDB의 제약 사항인 join과 transa-

ction에 대한 고려를 함께 해야 한다. 이러한 고려사항 때문에 2차례의 수정을 거쳐 마지막

구조를 만들었는데 아무래도 한 번 더 수정을 해야 할 것 같다.


처음에는 RDBMS 모델링을 하던 습관 때문인지 Element의 상태를 Sub Document로

만들었다. 구조는 다음과 같다


Elements Collection


{

    "_id" : ObjectId("58515bb94fe35068dc44bac3"),

    "_class" : "com.mazdah.tillsixty.goal.domain.Elements",

    "userId" : "584ff54a4fe35068dc44bab4",

    "goalId" : "584ff54a4fe35068dc44bab4_1",

    "elementType" : "A",

    "title" : "메인화면 구현",

    "description" : "Parallax 스타일의 메인화면 구현",

    "createDate" : "2016-12-14”,

“statusList” : [

{

“status” : “예정”,

“dueDate” : “2017-01-31”

},

{

“status” : “지연”,

“dueDate” : “2017-02-05”

},

{

“status” : “완료”,

“dueDate” : “2017-01-31”

}

]

}


이 경우 statusList를 통한 조회가 번거로워지기도 하고 또 상태 중 완료에 대한

처리가 모호해진다. 상태는 완료인데 날짜 필드를 dueDate라고 하기에도 뭔가

매칭이 안되고 그렇다고 완료의 경우에는 endDate라는 필드명을 쓰거나 아니면

endDate라는 필드를 추가하는 것도 데이터 구조의 일관성이 떨어지는 것 같다.


그래서 다시 다음과 같이 바꾸었다.


{

    "_id" : ObjectId("587e1e2b4216afd4103453c8"),

    "_class" : "com.mazdah.tillsixty.elements.domain.Elements",

    "userId" : "587e18514216afd4103453c2",

    "goalId" : "587e18514216afd4103453c2_1",

    "elementId" : NumberLong(1484660267204),

    "elementType" : "A",

    "title" : "Action ToDo 등록 테스트 2",

    "description" : "공공 데이터 중 선형회귀 분석으로 분석 가능한 데이터 구하기",

    "createDate" : "2017-01-17",

    "dueDateList" : [ 

        "2017-02-04", 

        "2017-01-31", 

        "2017-02-10"

    ],

    "endDate" : "2017-01-19",

    "status" : "완료"

}

간단해진 것은 좋으니 이 구조는 상태 이력을 파악하기가 쉽지 않다…ㅠ.ㅠ 즉, Timeline

처리가 어려워진다는 말이다. 결국은 상태가 바뀔 때마다 새로운 Document를 생성하고

같은 Element에 대해 상태별로 생성된 Document들은 group Id로 묶는 것으로 다시 

구조를 바꾸어야 할 것 같다.


중요한 것은 이렇게 Document를 바꿔나가는 동안 mongoDB쪽에는 한 일이 없다는

것이다. 이전 구조의 데이터를 삭제한 것 외에는 다른 어떤 작업도 필요 없었다. 바로

schemeless의 위력을 실감한 것이다. 하지만 바뀐 구조에 대한 프로그램 내에서의 

처리를 고려한다면 전체적인 의미에서의 작업이 단순해진 것은 아니다. 다만 DB쪽

작업이 개발쪽으로 옮겨왔을 뿐…ㅠ.ㅠ 그래도 역시 mongoDB 설계의 유연함은

상당히 만족스럽다.


Spring DATA REST


Document 구조가 바뀜에 따라 가장 크게 영향을 받는 것이 바로 REST API의 변경이

아닐까 싶다. 하지만 아직은 너무나 단순한 DB를 구현하고 있기 때문에 가장 기본적인

Query Method만으로도 충분히 처리가 가능하였다. 우선 Spring DATA REST에서

제공하는 keyword를 method 이름에 사용함으로써 웬만한 query는 다 처리가 되었다.

예를 들어 아래와 같은 REST 호출을 보자

“/rest/elements/search/findByUserIdAndGoalIdAndStatusInOrderByCreateDateAsc?” +

“UserId=” + userId + “&goalId=” + goalId + “&status=예정&status=연기


엄청 긴 API가 보인다. “findByUserIdAndGoalIdAndStatusInOrderByCreateDateAsc”

이름 만으로도 아마 충분히 짐작을 할 것이다. 이 API를 SQL Query로 바꾸면 다음과 같다.


select * from [TABLE]

where userId = [userId]

and goalId = [goalId]

and status in ([status1], [status2])

order by createDate asc


특별히 테이블 간의 join이 필요 없다면 이렇게 method이름만으로 대부분 처리가 가능하다.

mongoDB의 경우 join이 없다고 봐도 무방하므로 사용하기가 아주 편해진다.

Query method에 사용 가능한 keyword의 목록은 아래 문서에 자세히 정리되어있다.

문서에서 “Supported keywords inside method names”로 검색을 하면 keywords

테아블에서 확인 가능하다.


4. 참조 (site 또는 서적)


Spring Data JPA : http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.single-repository-behaviour 


5. 확인 사항 (의문 사항)


지난 시간에 목표했던 내용을 아직 확인 못했다. mongoDB에서의 트랜잭션 처리와 관련하여 

$isolated라는 연산자 확인이 필요하다.


6. 평가


애초에 DB에 대한 지식이 부족한 상태이다보니 모델링 작업은 쉽지 않았다. 나름대로 여기저기서

지식을 빌어다가 모델링을 해보기는 하였지만 아직도 완성된 모습은 아니다. 이렇게 간단한 시스템

개발에도 이럴진대…ㅠ.ㅠ 마음을 비우고 공부에 전념해야겠다.


일단 Till60의 기본적인 기능은 어느정도 구현되었으니 차주부터는 js쪽 소스들에 대해 React를

적용하는 작업을 본격적으로 시작해볼 예정이다. 조급해하지 말고 한발 한발 나가보자!

저작자 표시
신고



mongoDB 모델링을 해보자


처음 시작할 무렵의 글들에도 언급을 했지만 내가 지금 가지고 있는 지식이라고는 “몽고 디비 

완벽 가이드”라는 책 한권 읽은 것이 전부이다. 그마저도 변변한 선행 지식이 없이 읽었던 터라 

지금 기억나는 부분은 거의 없다시피 하다.


그나마 다행인 것은 내가 지금 하고자 하는 것이 mongoDB은 전반적인 내용을 알고자 하는 것이 

아니라 응용 프로그램을 위한 데이터 모델을 설계하고자 하는 것이기에 부담이 좀 덜하다는 것 

정도?


물론 읽기와 쓰기의 빈도를 고려하고 한 번에 저장할 수 있는 Document의 최대치라든지 성능을 

위한 정규와화 비정규화의 적절한 선택 등을 생각해보면 그래도 알아야 할 것들이 상당히 많다. 

그래서 조금이라도 그런 부담을 줄이기 위해 최대한 데이터 볼륨을 작게 하려고 한다(물론 

나중에는 점점 확장이 될 것이고 그 확장되는 부분도 고려해야 할 문제이긴 하다).


1. 기능 목표


전체 메뉴에 대해 Spring Rest API를 통해 mongoDB에 데이터의 CRUD 처리를 하는 

        기능을 구현한다. 대상이 되는 기능은 지난 주 작업했던 Sign-up을 제외하고 Login, 

        목표 등록, 목표 수정, 요소 등록, 상세 프로필 등록, 상세 프로필 수정 등이다.


2. 기술 목표


서두에 적었듯이 오늘은 mongoDB의 데이터 모델링을 해볼 예정이다. 이미 알고있는 바와 

        같이 mongoDB는 Document DB로 분류되어 JSON과 거의 동일한 형식으로 데이터가 저장

        되며 스키마가 없는 DB로 데이터 설계에 있어서 비교적 자유롭다는 장점이 있다. 더불어 

        mongoDB는 중첩된 Object를 가진 데이터 설계가 가능하다는 부분도 장점이다. 가능하면 

        이러한 mongoDB의 장점을 활용하는 선에서 단순하게 설계를 해보고자 한다.


3. 기술 적용 내용


본론에 들어가기 전에 먼저 mongoDB의 모델링 가이드에 대해 간단하게 살펴보고 시작

        하도록 하자.


일단 기존 RDBMS와의 용어상 차이를 보면 RDBMS의 Table은 Collection으로 Row는

        Document로 Column은 Field로 불린다. 앞서 언급한 것처럼 미리 데이터 구조를 정해놓고 

       그 구조에 맞는 데이터만 다룰 수 있는 RDBMS와는 달리 mongoDB는 매우 유연하게 

       데이터 구조를 사용할 수 있다. 심지어는 같은 Collection안에 전혀 다른 구조의 

       Document를 넣는 것도 가능하다. 그러나 당연한 얘기겠지만 같은 Collection에는 유사한 

       Document를 다루도록 하는 것이 관리상 편하다.


RDBMS는 그 이름에서도 알 수 있듯이 Table간의 관계가 매우 중요하다. RDBMS만큼은 

       아니지만 MongoDB에서도 Collection간의 관계를 적절하게 구성을 해야 성능상의 이점을 

       누릴 수가 있다. 


       이 때 중요하게 고려해야 할 것이 바로 “쓰기 작업에서의 원자성(Atomicity of 

          Write Operations)”이다. 조금 더 이해하기 쉽게 표현하자면 mongoDB는 한 번에 하나의 

       Document 또는 Collection에서만 쓰기 작업이 가능하다는 것이다. 즉, transaction이라는 

       것을 지원하지 않는다. 바로 이런 측면이 설계 상의 중요한 고려 사항이 될 것이다.


mongoDB 모델링은 크게 2가지 구조로 나눌 수 있는데 references와 embedded이다. 각각

다음과 같이 설명할 수 있다.


  • References : RDBMS의 정규화와 같은 개념으로 볼 수 있으며 Document를 다른 Collection에               배치하여 서로 참조하도록 구성하는 개념이다.


  • Embedded : 연관성이 있는 Document를 다른 Collection에 배치하지 않고 Document 내에 Sub Document로 배치하는 방법이다.




보다 자세한 내용은 공식 사이트의 문서를 참조하도록 하고 일단 이런 기본적인 사항만을 

        고려하여 Till60의 데이터 모델링을 진행해보도록 하자.


우선 RDBMS를 기준으로 Till60에 필요한 Table을 생각해보자. 아마도 아래 정도의 

        구성이 나올 것이다(컬럼은 Till60에 필요한 것 기준이다).


  • 사용자 기본 정보 (rowid, 이름, 사용자 ID, 비밀번호, 이메일 주소 등)
  • 사용자 부가 정보 (사용자 기본 정보의 rowid, 프로필 사진, SNS 계정 등)
  • 목표 정보 (사용자 기본 정보의 rowid, rowid, 목표 제목, 목표 설명, 시작일, 종료일, 목표 상태 등)
  • 요소 정보 (목표 정보의 rowid, 요소 rowid, 요소 제목, 요소 타입, 요소 설명 등)


이 내용을 기준으로 mongoDB에서의 Collection을 다음과 같이 구성해보았다.


  • 계정을 포함한 사용자 정보를 저장할 Profile Collection
  • 목표를 구성하는 각 요소를 저장할 Elements Collection


4개의 테이블을 2개의 Collection으로 바꾸었다. 이렇게 한 이유는 다음과 같다.


사용자 기본 정보와 사용자 부가 정보는 기본적으로 1 : 1의 관계이므로 사용자 부가 

        정보는 사용자 기본 정보의 Sub Document로 하여 같은 Profile Collection에 배치 하였다

(하지만 현재 상태로는 Sub Document가 아닌 같은 레벨의 field로 사용하고 있다).


다음으로 목표 정보는 사용자 정보와는 기본적으로 1 : N의 관계이다. 사실 Till60 개발

초반에는 “선택과 집중”이라는 모토 아래 사용자 1명 당 1개의 목표만을 설정할 수 

        있도록 구상을 했지만 그렇게 되면 아무리 장기 프로젝트를 위한 시스템이라지만 한 번 

        쓰고 버리는 시스템이 될 것이기에 생각을 좀 바꾸었다(하지만 아직까지는 사용자 1명 당 

        1개의 목표만을 생성할 수 있다). 이 경우 비록 1 : N이기는 하지만 N에 해당하는 목표가 

        얼마나 많이 생성 될 것인지를 생각해보면 그리 많을 것 같지는 않다. 아주 여유있게 

        예상하여 한 명의 사용가 이 시스템을 20년 정도 사용을 하고 그 기간 동안 6개월 짜리 

        목표를 꾸준히 만든다고 해도 목표는 120개 정도. 목표 자체의 정보 량이 많지 않기 

        때문에 한번에 불러오거나 메모리에 로드되기에 부담되는 양은 아니다. 이런 이유로 목표 

        정보 역시 사용자 정보의 Sub Document로 Profile Collection에 함께 배치하기로 하였다.


결국 사용자 정보, 사용자 부가정보, 목표 정보 3개의 정보가 하나의 Document로 동일한

Profile Collection에 배치되었다. 그리고 요소 정보의 경우 목표 정보와 1 : N의 관계에 

        있지만 그 증가량이 목표 정보에 비하면 상당히 많은 수이기 때문에 목표 정보에 

        embedded로 배치하기가 어렵다고 판단되어 references로 처리하여 별도의 Collection에 

        배치하게 된 것이다.


이렇게 구성된 데이터 구조를 보면 다음과 같다(앞서 말한 것과 같이 사용자 부가 정보는 

        아직 별도의 Sub Document로 분리하지 않았다).


Profile Collection


{

    "_id" : ObjectId("584ff54a4fe35068dc44bab4"),

    "_class" : "com.mazdah.tillsixty.account.domain.Profile",

    "name" : "우형준",

    "userId" : "mazdah",

    "password" : "w00hj8928",

    "email" : "woohj70@gmail.com",

    "facebook" : "100000967897658",

    "twitter" : "@mazdah70",

    "link" : "http://mazdah.tistory.com",

    "introduction" : "평범한 아들. 평범한 남자. 평범한 가장. 평범한 개발자. 평범한 서민. 하지만 그 

                                   '평범'이 너무도 싫은 한 사람",

    "goalList" : [ 

        {

            "goalId" : "584ff54a4fe35068dc44bab4_1",

            "goalTitle" : "Project Master 개발",

            "startDate" : "2016-12-13",

            "endDate" : "2017-12-31",

            "goalDescription" : "관리자와 개발자 모두 쉽게 사용할 수 있는 프로젝트 관리 툴 개발\n

                                                      프로젝트 진행 과정을 쉽게 시각화 문서화하여 진행 상태를 직관적으로

                                                      \n확인할 수 있도록 개발",

           "goalStatus" : "O",

           "createDate" : "2016-12-13"

        }

    ]

}


Elements Collection


{

    "_id" : ObjectId("58515bb94fe35068dc44bac3"),

    "_class" : "com.mazdah.tillsixty.goal.domain.Elements",

    "userId" : "584ff54a4fe35068dc44bab4",

    "goalId" : "584ff54a4fe35068dc44bab4_1",

    "elementType" : "A",

    "title" : "메인화면 구현",

    "description" : "Parallax 스타일의 메인화면 구현",

    "createDate" : "2016-12-14"

}


아직은 개발이 진행 단계이고 변경될 여지가 많이 남아있다. 당장에 현재 화면에서는 각 

        요소별 카운트가 표시되는데 많은 수의 요소가 누적된 경우 전체 카운트를 하는 것 보다 

        Profile Collection의 Sub Document의 목표 정보에 각 요소의 전체 수를 포함시키는 것이 

        어떨까 싶다. 다만 이럴 경우 트랜잭션 처리가 필요하기 때문에 아직은 고민 중이다.


어쨌든 이번 주에는 가장 기본적인 정보만을 가지고 Till60의 데이터를 모델링 해보았다.

하지만 여전히 아직 고려되지 않은 부분들이 많아 앞으로 많은 수정을 거치게 될 것이다.

오늘의 이 글은 그저 mongoDB의 모델링을 맛보기 한데 의의를 두어야 할 것 같다.


4. 참조 (site 또는 서적)


mongoDB 문서 중 모델링에 대한 부분 : 

        https://docs.mongodb.com/manual/core/data-modeling-introduction/


5. 확인 사항 (의문 사항)


mongoDB에서의 트랜잭션 처리와 관련하여 $isolated라는 연산자가 있는데 이를 어떻게 

        사용하는지 공부를 좀 해두어야 겠다.


6. 평가


사실 워낙 작은 규모의 시스템이고 필요한 데이터도 많지 않았기에 가장 기본적인 내용만 

        확인한 후 바로 작업을 진행해보았다. 하지만 앞으로 추가될 정보들(이미지나 동영상 

        등의 미디어 정보)과 성능 또는 기능 상의 문제로 변경될 구조들(요소 count 정보 처리나 

        실제 목표를 다수 등록할 수 있게 한 이후의 처리 등)을 생각해보면 아직도 진행되어야 할 

        내용이 보여진다. 우선은 이 기본 상태에서 UI를 좀 더 손본 후 본격적으로 기능적인 

        부분을 진행해야 겠다.

저작자 표시
신고



Spring boot와 mongoDB 연동하기 그리고 REST API


새삼스러운 이야기지만 Spring boot는 프로젝트 구성이 참으로 간편하다.

처음 STS에서 프로젝트 생성 시 Dependencies를 적절하게 선택하면 필요한 모든 라이브러리들이

알아서 착착 들어와주고 우리는 그저 그 라이브러리들을 적절히 사용하기만 하면 된다.


오늘 정리할 Spring boot와 mongoDB의  연동과 이를 테스트하기 위해 필요한 REST API 구현도

마찬가지이다.


그래서 어찌 보면 오늘 내용은 달리 설명할 부분이 없는 것이나 다름 없다.

아무래도 일반적인 지식으로 내용이 채워질 것이다.



1. 기능 목표


이번 주의 목표는 Spring boot와 mongoDB를 연동하여 Sign-up 정보를 mongoDB에

저장하고 이 정보를 이용하여 Login을 하는 것까지 구현을 하게 될 것이다.


2. 기술 목표


Spring boot와 mongoDB의 연동 및 이 과정에서 필요한 Spring boot에서의 REST API

구현에 대해 알아보도록 할 것이다.


3. 기술 적용 내용


  • Spring boot와 mongoDB 연동


Spring boot와 mongoDB의 연동 및 이 과정에서 필요한 Spring boot에서의 REST API

구현에 대해 알아보도록 할 것이다. 


우선 mongoDB는 설치가 된 것을 가정하고 설명을 진행한다. 나같은 경우  OSX에서 brew로

설치를 진행하고 설치 후 변경된 내용은 없다. 즉 가장 기본적인 상태로 설치가 되어있다.

그리고 Till60라는 이름의 DB를 하나 생성하였다. (MomgoDB를 인증모드로 접근하기 위한

설정 작업들이 있기는 하였으나 mongoDB 자체에 대한 설명을 하는 자리가 아니므로

‘4. 참조 (site 또는 서적)’ 항목에 링크로 대신한다.


내용을 단순하게 하기 위해 STS에서 새로 프로젝트를 생성하였다. Spring Starter Project를 

선택하였으며 Dependencies도 단순하게MongoDBWeb만을 선택하였다. 이렇게 생성했을 때 

gradle.build 파일의 dependencies는 다음과 같다.


dependencies {

compile('org.springframework.boot:spring-boot-starter-data-mongodb')

compile('org.springframework.boot:spring-boot-starter-web')

testCompile('org.springframework.boot:spring-boot-starter-test')

}


그리고 application.properties에는 mongoDB 연결을 위한 uri를 다음과 같이 설정하였다.


spring.data.mongodb.uri=mongodb://mazdah:password@localhost:27017/Till60


사실상 설정은 이 것이 다라고 보면 된다.


  • Spring boot REST API 구현


이전의 개인프로젝트나 업무상의 작은 프로젝트에서는 주로 @RestController를 이용하여 REST API를

구현했었다. 그런데 이번에 @RepositoryRestResource라는 annotation을 새롭게 알게 되고 그

간편함에 끌러 사용하게 되었다. 물론 후에 또 어떻게 바뀔지는 모르겠지만…


우선 @RepositoryRestResource는 spring-data-rest-core 라이브러리에 정의되어있으며 이는

Spring Starter Project 생성시  Dependencies에 Rest Repositories를 선택하면 포함된다.


주의 사항

나같은 경우 현재 사무실과 집에서 Git으로 소스를 공유하면서 작업을 하고 있는데 두 곳의 STS 버전이

달라서 그런지 아니면 프로젝트 생성 후 별도로 라이브러리를 추가한 것이 꼬였는지 처음 사무실에서

@RepositoryRestResource를 사용했을 때 브라우저에서 계속 404 에러가 발생을 했다.

확인 결과 필요한 라이브러리 중 spring-data-rest-webmvc가 빠져있어서 발생을 한 문제였다.

기왕에 Spring boot를 사용하기로 했으면 필요한 라이브러리를 일일이 찾아 삽입하기 보다는

 처음 프로젝트 생성시 Dependencies를 잘 설정해주는 것이 불필요한 오류를 막는 지름길 일 것이다.


 

@RepositoryRestResources는 Repositary 인터페이스에 적용을 하게 되며 이렇게 할 경우

별다른 RestController 없이 기본적인 REST API를 자동으로 생성해준다. 이 때 자동으로 생성되는

REST API의 기본 형태는 다음과 같다.


http://domain:port/{domain}

http://domain:port/{domain}/{id}

http://domain:port/{domain}/search

http://domain:port/{domain}/search/{search query}


이 때 domain은 @Entity 또는 @Document 등으로 설정된 Domain 클래스이며 내부적으로

클래스명의 앞부분을 소문자로만든 후 뒤에 s를 붙여 사용하게 된다. 즉, Person이라는 Domain

Class를 만들었다고 한다면 {domain} 위치에는 persons로 표시된다.


{search quesry}에는 Repository 인터페이스에 선언된 쿼리 함수와 그 함수의 파라미터로 전달될

쿼리 문자열이 들어가게 된다. 만일  findByName(@Param(“name”) String name)이라는 

쿼리 함수가 선언되어있다면 {search quesry}는 다음과 같이 표현된다.


findByName?name={name}


Person domain 객체를 이용하여 이름이 “Edison”이라는 사람을 찾는다면 전체 URI는 다음과 같다.


http://domain:port/persons/search/findByName?name=Edison


참고로 URI의 구성에 영향을 미치는 요소가 2가지가 있는데 우선 REST API의 베이스 URI를

Spring boot의 application.properties에 spring.data.rest.base-path라는 항목에 값을

넣으면 된다. 만일 이 값을 api로 지정했다면 위의 URI는 다음과 같이 바뀌게 된다.


http://domain:port/api/persons/search/findByName?name=Edison


그리고 @RepositoryRestResources에 path 요소를 설정하게 되면 앞서 말한 domain 값이

path에 설정한 값으로 바뀌게 된다. 즉, @RepositoryRestResources(path=“user”)로

설정을 하게 되면 위의 URI는 다시 아래와 같이 바뀐다.


http://domain:port/api/user/search/findByName?name=Edison


이렇게 이번 주에는 가장 기본적인 설정을 통해 Spring boot와 mongoDB를 연동하고 

Sign-up과 Login 기능을 구현하게 되었다.


4. 참조 (site 또는 서적)


Spring Rest 참조

http://docs.spring.io/spring-data/rest/docs/current/reference/html/

https://brunch.co.kr/@sbcoba/3


MongoDB 관련 문서

http://blog.nekoromancer.kr/2013/12/16/mongodb-인증모드로-접속하기/

https://docs.mongodb.com/manual/reference/method/db.createUser/#db.createUser


MongoDB 관리 툴

https://docs.mongodb.com/ecosystem/tools/administration-interfaces/

https://www.humongous.io/app/


5. 확인 사항 (의문 사항)


이처음 생성하고 현재 프로젝트를 진행하고 있는 Till60 프로젝트의 경우 Run As > Spring Boot App

하여  서버 기동을 하게 되면 아래와 같은 로그가 계속 표시된다.


23:40:47.916 [cluster-ClusterId{value='584c13e54fe3502b024dca36', description='null'}-localhost:27017] DEBUG org.mongodb.driver.cluster - Checking status of localhost:27017

23:40:47.918 [cluster-ClusterId{value='584c13e54fe3502b024dca36', description='null'}-localhost:27017] DEBUG org.mongodb.driver.cluster - Updating cluster description to  {type=STANDALONE, servers=[{address=localhost:27017, type=STANDALONE, roundTripTime=1.1 ms, state=CONNECTED}]


아마도 클러스터로 구성된 mongoDB의 ping check를 하는 로그인 듯한데 얘가 어디서 출력을 하고

있는 것인지 잘 모르겠다. 로그에 찍힌 패키지명으로 추측컨대 mongo-deriver 또는 mongo-java-

Driver라는 라이브러리에서 찍히는 것 같은데 Referenced Library에는 해당 라이브러리가 포함되어

있지 않다. 아직도 기본 구조를 이해를 못하고 있어 애로 사항이 좀 있다…ㅠ.ㅠ


아마도 클러스터로 구성된 mongoDB의 ping check를 하는 로그인 듯한데 얘가 어디서 출력을 하고

있는 것인지 잘 모르겠다. 로그에 찍힌 패키지명으로 추측컨대 mongo-deriver 또는 mongo-java-

Driver라는 라이브러리에서 찍히는 것 같은데 Referenced Library에는 해당 라이브러리가 포함되어

있지 않다. 아직도 기본 구조를 이해를 못하고 있어 애로 사항이 좀 있다…ㅠ.ㅠ


6. 평가


서두에서도 말했지만 Spring boot는 우선 설정에 큰 신경을 쓰지 않아도 좋기 때문에 작업 시간을

꽤 많이 단축시켜준다. 하지만 그 구조를 이해하지 못하는 경우에는 상당한 혼란도 생길 수 있다.

모든 기술들이 그렇겠지만 우선은 그 기본적인 내용을 이해하고 사용을 해야 겠다는 생각을 새삼

하게 된다.


어쨌든 이번 주에는 어렵지 않게(물론 이해 못하는 부분이 있기는 하지만) mongoDB와 연동을

하여 기본적인 CRUD는 처리할 수 있게 되었다. 더 진도를 나가기 전에 mongoDB 모델링이

필요할 것 같다. 다음 주에는 mongoDB 모델링에 대해서 진행을 해 볼 것이다.

저작자 표시
신고



Till60 1차 개발분 Prototype 개발


그간 SessionDB도 만들고 또 개발과는 별개로 뻘짓도 하느라 prototype 만드는데만 근 5주가

걸렸다. 아무래도 하루 1~2시간 밖에 할애를 하지 못하다보니 실제로는 한 일주일 정도가 걸렸다고

볼 수 있으나 그래도 애초 예상한 것보다는 시간이 많이 걸렸다. 그나마 앞서 만들어놓은 

SessionDB가 꽤 효과를 봤다.


이번 포스팅부터가 본격적인 개발 관련 내용으로 앞으로의 글은 이 포스팅의 포맷을 유지하면서

연재 될 예정이다. 다만 포스팅 기준으로 기능 개발을 위주로 할 것인지 새로운 기술에 대한

학습 정보를 위주로 할 것인지 아직 방향을 정하지 못해 당분간 조금 혼란스러울 수도 있겠다.



Github : https://github.com/mazdah/TillSixty

Prototype 주소 : http://121.160.87.10


*** Prototype 주소는 내 개인 PC의 주소로 언제 서비스가 내려갈지 모름…-.-

*** 개발 중인 소스가 서비스에 올라와 있으므로 시시각각 화면이 바뀌거나 오류가

       발생할 수 있으며 의미없는 팝업 등이 뜰 수 있음

*** 아래도 설명하겠으나 데이터는 localStorage를 이용하므로  서비스를 이용한 PC의 

       브라우저에만 저장이 됨. 데이터를 삭제하려면 브라우저 설정에서 인터넷 데이터를

       삭제 하면 됨

*** 누누히 말하지만 나는 코드가 개판이어도 초반에 빨리 개발한 후 코드를 개선해 나가는

       방식을 선호하므로 현재 코드는 개판임…-.- 앞으로 얼마나 개선될지도 장담 못함…ㅠ.ㅠ 



1. 기능 목표


다음과 같은 기능 구현을 목표로 삼았다.

  • 로그인
  • 목표 등록 (등록 및 수정)
  • 요소 등록 (등록 및 조회)
  • 챠트 구현 (Radar 챠트, Bar Chart, Line Chart)


목표 외 구현 내용

  • 타임라인 구현
  • 캘린더 구현


2. 기술 목표


- Github

  기본 repository로 Github를 이용. 아래 설명하는 Jenkins와 연동하여 Push가 일어날 때마다

  Jenkins에서 빌드가 실행되도록 설정을 하였다. 


- Jenkins (Gradle 빌드 미설정)

  아직까지는 기본적인 설정에 정적분석을 위한 플러그인을 설치한 정도. 아직 서버 프로그램이 

  만들어지기 전이라 특별한 작업 진행은 없다. 하지만 Github와의 연동으로 Github에 push가

  발생할 때마다 빌드가 실행된다.


- Gradle (의존성만 설정)

  라이브러리 의존성 설정 및 기본적인 빌드 설정


- Spring boot (미적용)

  Web 프로그램 구현


- Bootstrap

  화면 UI 구현


-JQuery

  Front end 기능 구현.


- React (미적용)

  화면 UI를 위한 컴포넌트 구현


- MongoDB (미적용)




3. 기술 적용 내용


- Github와 Jenkins 연동

  위에 언급한 바와 같이 Github에 push가 발생하면 Jenkins에서 빌드가 실행되도록 설정하였다.

  이에 대한 설정은 Github쪽에서 확인할 수 있는데 repository가 있다는 전제 하에 Settings 메뉴의

  integration & Services 메뉴로 들어가면 아래 이미지와 같이 연동할 서비스를 선택하게 된다

  (엄청 많은 Service 들이 설정 가능하다).




  여기서 Jenkins (Git plugin)를 선택하면 아래 이미지와 같이 화면이 바뀐다. 아래 화면에서

  Jenkins url에 자신이 사용할 Jenkins의 url을 입려한 후 가장 아래의 Add Service를 클릭하면

  연동이 된다. Jenkins쪽 설정은 아래 화면의 상단에 있는 Install Notes를 참조하면 된다.




- Bootstrap

  대부분 오픈소스를 가져다 사용했다. 그나마 직접 작업한 부분들도 모두 Bootstrap으로

  화면을 구성하였다. Bootstrap의 경우 달리 설명이 필요없을 정도로 사용이 쉽다. 


- JQuery

  이번 개발 단계에서는 DOM 처리와 SessionDB 연동을 위해 사용하였다. 아직 Back end가

  구현되기 전이기 때문에 ajax 처리는 없고 대체로 SessionDB에서 가져온 데이터를 화면에

  뿌려주기 위해 DOM 처리를 한 내용이 전부다.


아직 Prototype을 만든 것에 불과한데다가 자바 프로그램이나 DB 연동이 전무한 상태이기에

다른 기술들은 전혀 적용이 되어있지 않다. Spring boot 역시 현재로서는 그냥 단순한 웹서버에

불과한 상태다.


React의 경우 우선은 빠른 Prototype 제작을 위해 적용을 뒤로 미루었다. 추후 리팩토링을

거치면서 반복되는 DOM 객체들은 모두 React 컴포넌트로 변경할 예정이다.




4. 참조 (Open source, site 또는 서적)


- Chart 

  이름 : D3, ndv3

  Site : https://d3js.org

             http://nvd3.org


- Profile 영역, 상단 Navigation, Timeline

 Site : http://bootsnipp.com


- Calendar

  이름 : fullcalendar

  Site : https://fullcalendar.io


- Datepicker

  이름 : bootstrap-datepicker

  Site : https://bootstrap-datepicker.readthedocs.io/en/latest/



5. 평가 및 다음 목표


일단 이번 프로토타입 개발의 가장 큰 소득은 중간에 삼천포로 빠져서 만든 SessionDB이다.

사실 이걸 만들 때만 해도 서버단과 DB 구현 없이 이정도로 작동하는 프로토타입을 만들게

될 줄 몰랐다. 물론 localStorage를 사용한다는 부분에서 발생하는 한계는 있지만…


하지만 중요한 문제는 Till60의 윤곽이 서서히 드러나면서 역시나 애초에 계획하고 예상했던

것과 뭔가 다른 모습에 당황스럽기까지 하다…-.-


사실 뭔가 집중적으로 인생의 마스터 플랜을 관리할 수 있는 서비스를 만들어보고자 하는 것이

최초의 목표였는데 만들어진 모습은 너무나 산만하다. 처음에는(물론 지금도…) 이게 뭐하는 

서비스인지도 잘 모를 정도였는데 그나마 사용자 등록 후 Wizard 형식의 Tutorial을 간단하게나마

추가를 해서 좀 나아지긴 한 것 같지만 여전히 집중되는 뭔가가 없이 산만하다는 느낌을

지울 수가 없다.


일단 UI/UX를 다시 한 번 고민해봐야겠다.


아무래도 Till60는 프랜B를 위한 플랜A가 될 가능성이 높을 것 같다…-.-


이번 주말은 휴식의 의미로 한동안 손을 못댔던 아두이노 로봇을 손좀 보고 다음주부터는

본격적으로 Back end 작업을 시작하면서 Spring boot와 mongoDB를 공부해보기로 하겠다.

저작자 표시
신고

SessionDB 개발 (Web Storage를 이용한 간이 DB)


원래는 이번 주에 Till60의 Prototype을 개발해서 전체적인 흐름을 한 번  짚어볼 예정이었다. 항상 구체적인 무엇인가로부터 출발하는 것이 

보다 명확한 진행을 가능학 해준다고 믿고 있는 나로서는 Prototype 개발은 꽤나 중요한 과정이다.


그런데 어느정도 동작 가능한 Prototype을 개발하려 했더니 아무래도 데이터 처리를 위한 준비가 번거로웠다. 물론 H2 Database같은 

In-memory db가 지원되어 간편하게 사용할 수 있지만 Prototype 개발에는 그조차 사치로 여겨졌다. 좀더 간편하게 데이터 흐름까지

짚어볼 수는 없을까?


곰곰이 생각을 하다가 sessionStorage를 이용해보는 것은 어떨까 하는데 생각이 미쳤다. 많은 제약이 있기는 하지만 개인 프로젝트의

Prototype을 만드는 정도에는 충분히 역할 할 것 같았다. 기왕 생각이 여기에 미친 바에는 차라리 제대로 기능을 만들어보자고 결심하고 

이틀간 열심히 지지고 볶아 sessionStorage와 localStorage를 DB처럼 사용할 수 있는 javascript 모듈과 AdminLTE UI 라이브러리를

이용해 Admin 화면까지 만들어보았다.


시스템에 대한 자세한 내용은 링크로 대신하고 이 글에서는 간단하게 화면 구성과 사용법을 적어보고자 한다.


소스코드 : https://github.com/mazdah/SessionDB



간단한 소개


앞서 말한대로 이 툴은 sessionStorage와 localStorage를 DB 처럼 사용할 수 있게 만든 툴이다. 가장 큰 장점이라면 아무런 설정 없이

바로 DB  처럼 사용 가능하며 단 하나의 파일로 CRUD의 처리를 모두구현할 수 있다는 점, 그리고 네트워크 연결 없이도 로컬에서 DB와 유사한

기능을 사용할 수 있어 프로젝트 초기 아무런 세팅도 안되어 있어 멍청한깡통 PC가 되버린 개발 PC에서도 충분히 흐름을 짚어볼 수 있다는 

점이 장점이라고 할 수 있을 것이다. 그리고 기본 javascript로 구현되어있어다른 javascript 라이브러리도 필요가 없다. 다만 Admin화면을 

위해서는 JQuery와 Bootstrap이 필요하다.


다만 Web Storage 기반인만큼 RDBMS보다는 NoSQL에 가깝고 데이터를 원격으로 공유할 수 없다는 점 등은 단점이 될 것이다.

하지만 데이터 공유 문제는 Export/Import 기능으로 어느 정도 만회가 될 수 있을 듯하다.


기능 설명


일단 초기 화면은 다음과 같다. Dashboard에서는 sessionStorage와 ocalStorage에 생성된 테이블의 갯수와 목록, 그리고 각 테이블에

생성된 데이터의 갯수가 표시된다.





좌측의 메뉴를 보면 가장 상단에는 sessionStorage와 localStorage를 선택하는 select 컨트롤이 있다. 이후 작업은 여기서 선택한 

storage에서 일어나게 된다.


다음은 앞서 본 대시보드로 이동하는 메뉴이며 3번째 메뉴는 생성된 테이블 목록을 보여주는 메뉴이다. 각 테이블 이름을 클릭하면 해당 

테이블에 대한 작업을 할 수 있는 화면으로 이동한다.


다음은 Create Table 버튼으로 이 버튼을 누르면 테이블 생성 화면으로 이동한다. 마지막으로 sessionStorage를 주로 이용하게 되므로 

Admin 화면에서 바로 테스트용 페이지로 이동 가능하도록 페이지 이동 기능을 추가하였다. Input 박스에 이동할 페이지 경로를 입력하고 

Go 버튼을 클릭하면 현재 윈도우에서 해당 페이지로 이동하게 된다.




먼저 Create Table 버튼을 클릭하여 테이블을 생성해보자. 테이블 생성은 매우 간단하며 테이블 이름을 입력한 후 Create Table 버튼을 

클릭하면 테이블이 생성된다. 물론 앞서 말한 것처럼 좌측 상단에 선택한 storage 영역에 테이블이 생성된다. 테이블은 아주 간단하게

 {“table”:[]}의 구조로 만들어지며 앞으로 table을 Key로 하는 배열 영역에 데이터들이 저장된다.





테이블을 생성했으니 이제 데이터를 insert 해보자. SessionDB는 스키마가 없는 JSON 기반의 DB이다. 따라서 테이블 생성시에는

아무런 구조 없이 그냥 빈 배열 하나가 만들어진다. 따라서 최초에 데이터를 입력할 때는 아래 그림과 같이 JSON 포맷으로 문자열을 

입력해주어야 한다.



아래와 같이 입력되었다.



하지만 한 번 데이터가 들어간 이후에는 입력된 데이터의 key를 기준으로 가상의 컬럼을 생성한다. 따라서 데이터 입력 시 아래와 같은 화면이 

나타난다.

데이터 입력시 편의를 위해 이렇게 구성은 하였으나 이로 인해 schemeless의  유연성이라는 장점은 포기했다. 즉, 한 테이블의 모든 데이터는 

동일한 갯수와 이름의 key로 구성되어야 정상적으로 사용이 가능할 것이다.


입력된 데이터는 테이블 화면에 목록으로 보여지며 항목 우측에 삭제와 수정 버튼 그리고 하단에 Export, Import, Drop Table 등의 기능 

버튼이 있다.


차례차례 살펴보면…

삭제 버튼은 당연히 데이터를 지우는 기능이다. 클릭하면 데이터가 바로 지워진다. 수정으 Update 기능에 해당하며 클릭하면 아래 이미지와 

같은 팝업이 뜨고 내용을 변경한 후 Update Row 버튼을 클릭하면 데이터가 수정된다.




Export Table 버튼을 클릭하면 화면 하단의 Textarea에 테이블 전체 데이터가 JSON 포맷의 문자열로 표시된다. 다만 기본 테이블 구조와 

다른 것은 tableName Key가 추가되어있다는 것이다. 이 문자열을 그대로 복사해 다른 PC에 설치된 툴에서 Import Table을 이용하면 

불편하나마 데이터를 공유할 수 있다.




Import Table은 Export Table을 했을 때 출력되는 포맷의 JSON 문자열로 테이블에 데이터를 입력하는 기능으로 2가지 옵션이 있다. 

각각의 이름대로 추가하기를 선택하면 기존 데이터에 Import 할 데이터가 덧붙여 지며 대체하기를 선택하면 기존 데이터는 삭제되고 새로운 

데이터로 테이블이 채워진다.


추가하기 선택 시


대체하기 선택 시



마지막으로 Drop Table은 이름 그대로 테이블 자체를 삭제해버리므로 저장된 데이터도 모두 지워진다.


이와 같은 기능으로 필요한 테이블과 테스트용 데이터를 미리 생성한 후 테스트 페이지들을 API를 이용해 구현하여 사용하면 쉽게 데이터 

처리가 가능한 Prototype을 만들 수 있을 것이다.


아직도 개선할 부분이 많이 보이지만 일단 개인적인 목적으로 만든만큼 써가면서 필요한 부분을 수정해 나가야겠다.


이제 다음주 부터는 진짜로 Till60 Prototype 개발에 집중해야겠다~

저작자 표시
신고


조금은 쪽팔린 일일 것 같지만 너무나 황당하고 기뻐서 짧게나마 쓴다.


매번 javascript에서 JSON.stringify(jsonObj); 하고나서 읽기가 불편해서 편집기에서 줄바꾸는 개고생을 했는데...


옵션이 있었을줄이야...ㅠ.ㅠ



JSON 객체의 stringify 함수는 기본 파라미터인 json 객체 외에 옵션으로 2개의 인자를 더 넘길 수 잇는데,

두 번째 인자는 일종의 filtering 기능을 하는 파라미터로 json 객체의 key와 value를 파라미터로 받아

지지고 볶은 후 그 결과만 리턴을 해주는 기능을 한다(자세한 것은 이곳 참조 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). 이 기능도 잘 활용하면 큰 도움이 될 것 같다.


그리고 중요한 마지막 파라미터가 바로 json 포맷의 문자열을 정렬해주는 기능을 한다.

단순히 숫자를 입력하면 space를 숫자만큼 띄우고 그밖에 escape 문자로 '\t' 등을 입력하여 적절한 indent를

줄 수 있다.


다음은 각각 그 예이다.


$('#_query-area').val(JSON.stringify(tableObj));


결과


{"table":[{"name":"우형준","id":"abcd","password":"abcd1234","email":"aaa@bbbl.com","_id":"0"}],"tableName":"UserTable"}


$('#_query-area').val(JSON.stringify(tableObj, null, 4));


결과


{

    "table": [

        {

            "name": "우형준",

            "id": "abcd",

            "password": "abcd1234",

            "email": "aaa@bbb.com",

            "_id": "0"

        }

    ],

    "tableName": "UserTable"

}


역시 공부해야 한다...ㅠ.ㅠ;

저작자 표시
신고


프로젝트에 적용할 기술들


Till60 프로젝트를 진행하면서 다음과 같은 기술들을 적용해 볼 것이다.

앞선 글에서도 언급했지만 대다수가 아직 실무적으로 사용해 본 적이 없는

기술인만큼 많은 시행착오를 거쳐야 할 것으로 보인다.


1. Language


일단 가장 익숙한 java로 시작한다. 새로운 API를 사용할 일은 없을 것 같지만

버전은 1.8로 한다.





2. Framework (Back end)


가장 기본이 되는 프레임워크로는 Spring Boot를 이용할 계획이다.

아직은 시험삼아 잠깐 이용해본 정도지만 무엇보다 설정이 간단하다는

점이 가장 매력적이다. 그리고 stand-alone 애플리케이션을 만들 수

있다는 점도 거창한 WAS 설정을 생략하게 해주어 작업을 가볍게 할

수있다. 버전은 현재 GA(General Availability, General Acceptance)

버전인 1.4.1을 선택했다.





3. Framework (Front end)


애초 계획은 Angular JS + Bootstrap 조합으로 가려 했는데 한동안

손을 안 댄 사이 Angular JS 2.0이 발표되었고 1.X와는 너무나 달라져

사용할 엄두가 안났다. 그래서 이참에 아직 배워보지 않은 React를 써보기로

했다. 물론 React를 사용하기로 한 진짜 이유는 Angular JS가 Framework

급이라면 React는 UI 전담의 라이브러리 급이라는 이유도 있다. 일단은

최대한 가볍게 갈 수 있으면 좋다.


아직 미묘하게 혼란 스러운 것이 React도  UI쪽이고 Bootstrap도 UI쪽인데

서로 어떻게 다르고 어떻게 조합을 해야 할지 잘 모르겠다. React-Bootstrap

이라는 프로젝트도 진행되고 있는 것 같던데…


마지막으로 서버단이 java 기반이므로 서비스 호출은 jQuery로 처리하려고 한다.


사용할 버전들은 다음과 같다.


React : 15.3.2

Bootstrap : 3.3.2

JQuery : 3.1.1






4. DB


애초 계획은 MySQL로 하려고 했는데… 은근히 NoSQL에 대한 욕심이 생겨 

mongoDB로 선택을 했다. 어차피 RDBMS로 하더라도 제대로 된 모델링이 

되지 않을 것이기도 하거니와 새로운 것을 익히는 것도 이 프로젝트의 목적 중

하나이니만큼 처음으로 mongoDB에 도전을 해보고자 한다. 게다가 3.X 버전에는

$lookup이라는 join과 유사한 기능을 지원한다고 하니 한 번 써볼만 할 것 같다.

사용할 버전은 3.2.10이다.





5. CI (Continuous Integration)


가장 포괄적인 부분인 듯싶다. 그냥 단순히 나열을 해보면 build를 위해서는

Gradle을, 형상관리를 위해서는 GitHub를 좁은 의미의 CI를 위해서는 jenkins를

사용할 예정이다. gradle은 처음이나 다름없어서 공부를 좀 해야 할 것 같고

GitHub는 단순 형상관리용도로 좀 써보긴 했지만 깊은 내용은 모르고 그나마

jenkins는 현재 업무에서 모바일(안드로이드와 iOS 모두) 빌드용으로 설정하여

사용 중인데 막강한 플러그인들이 많아서 좋다. 특히 소스의 정적 분석 관련

플러그인들이 많은 도움이 되는 것 같다. GitHub와 jenkins 연동은 공부를 좀

해야 할 것이다.





6. Mobile


사실 테스트용 앱을 배포하고 테스트 하기에는 안드로이드 쪽이 좀 수월하지만

명색이 iOS 개발자인데 아직 Swift로 제대로된 앱을 개발해본 적이 없기에 iOS의

Swift를 선택했다. 추후 안드로이드도 개발할 예정





7. Container


요즘 많이 언급되는 아키텍처 중 하나가 마이크로 서비스, 그리고 마이크로 서비스를 

구현하는 기반 기술로 Docker가 자리잡고 있다. 아직 마이크로 서비스의 개념 조차

제대로 이해하지 못하는 상황에서 잘 구현이 될지는 모르겠지만 Docker를 이용한

마이크로 서비스 구현도 이번 프로젝트의 목표 중 하나다.






거듭 강조하지만 상당히 많은 기술들을 다루지만 대부분이 처음 접하는 기술들이다.

과연 얼마나 해낼 수 있을지는 의문이지만 차근차근 진행을 해보고자 한다. 어차피

프로젝트 이름이 Till60이다. 60살까지는 아직 13년이 남았고 차근차근 익히다보면

그 때까지는 뭐 하나 남지 않을까…하고 막연히 기대해본다~


다음부터는 본격적으로 프로젝트 일지를 적어보도록 하겠다.



저작자 표시
신고


프로젝트를 시작하면서…


쉴드부터 치고 가자…-.-


나는 현재 경력 16 10개월차의 개발자이다.

2009년까지는 JAVA 개발을 주력으로 하다가 2010년부터 iOS 개발로 방향을 선회한

지금에 이르고 있다.


전공은 국어국문학이며 대략 1994 무렵 중앙정보처리 학원이라는 곳에서 

C/C++ MFC 관련 교육을 5개월 정도 받은 것이 IT 교육의 전부이다.


이러한 이력이 내게 가져다 주는 것은 끝없는 의심이다.

내가 제대로 것인가?’

누군가가 나의 실력을 의심하고 있지는 않은가?’

나은 방법을 어떻게 찾아야 하는가?’ 등등


프로젝트를 진행하면서도 이같은 질문들은 계속 것이다.

특히나 이번 프로젝트에 적용하고자 하는 기술 절반은 번도 경험해보지 못한

기술들이며 나머지 기술들도 본격적인 실무에 적용해 적이 없는 기술들이다.

결국 끊임없이 검증을 받아야 하는 상황이지만 아마 아무도 검증을 해주지 않을 것이다.


그러면서 한편으로는 나만의 방법론과 산출물들을 정립하고 것이 일반적으로도

적용돌 있기를 야무지게 꿈꿔본다.


그래서 글을 꾸준히 읽을 독자들이 있다면 미리 사죄의 인사를 드린다.



Till60 어떤 의미인가?


고령화 사회가 되면서 사실상환갑 의미가 없어졌다.

이제는 60 정도의 어르신들을 할아버지라고 부르기도 민망할 정도다.

그리고 내가 나이가 되기까지는 앞으로도 무려 13년이라는 시간이 남아있다.

물론 나보다 많은 시간이 남은 사람들도 있고, 적은 시간이 남은 사람들도 있을 것이다.


비록환갑 의미가 퇴색되었다고 할지라도 본래의 , 60갑자를 한바퀴 돌고

다시 시작한다는 의미 만큼은 아직도 분명한 가치가 있다고 생각한다.

아직 우리에게는 다시 시작할 있는 시간들이 남아 있다.


것이 처음의 시작이든 다시 하는 시작이든 목표를 정하고 목표에 매진하는 것이

삶에 있어서 얼마나 소중한가 하는 것은 필요가 없다.


지금까지 나온 생산성 카테고리에 넣을만한 서비스들이 주로 단기 계획 위주의 To-Do 또는

프로젝트 관리 시스템인데 비해 Till60 조금은 여유롭게 중장기 목표를 수행하도록

도와주는 시스템이라 생각하면 것이다.



어떤 요소들이 있는가?


To-Do 프로젝트 관리 시스템들이 짧은 시간을 전제로 하다보니 일정관리나 단편적인

목표를 실행 했는가에 대해 집중하는데 비해 Till60 목표를 이루기 위해 필요한 요소들을

하나 하나 모으고 그렇게 모은 것을 어떻게 조합하고 활용하는지에 집중하고자 한다.


우선 당연히 목표를 설정해야 것이고

목표를 이루기 위해 일반적으로 필요하다고 생각되는 4가지 요소를 배치해 보았다.

자원 (금전, 시간, 공간, 그밖의 물질적 요소), 멘토 (인적 요소), 정보 (지적 요소), 위험 (회피 해야 요소)

그리고 요소들을 수집하거나 제거하는활동이라는 핵심 요소를 추가하였다.


아직까지는 일반적인 상황을 염두에 두고 있으나 점차 목표의 특성에 따라 다양한 요소들을

구성할 생각이다. 이전 글에서 언급한 Scrivener처럼 말이다.








어떻게 만들어갈 것인가?


우선은 간단한 시스템으로 시작을 것이나 모바일 앱도 거의 같은 시점에 병행하여 개발 것이다.

자기 계정을 만들고, 간단한 프로필을 생성하고, 목표를 설정하고 바로 위에 언급한 요소들을

등록하는그리고 이러한 활동을 시각화 것이고 Social 것이다.

아직 뚜렷한 일정은 나오지 않았지만(아마도 프로젝트가 끝날 때가지 나오지 않을 것이다…^^;)

대략적인 단계는 다음과 같이 정해두었다.


1 개발


1. 로그인

  . 계정정 생성

  . 계정 로그인

  . SNS 연동 로그인


2. 프로필 등록

  . 사진 등록

  . 간단한 소개 등록

  . SNS계정 또는 블로그 주소 등록


3. 목표 등록

  . 목표 5가지 요소 등록

  . 공개여부 선택


4. 챠트를 통한 시각화

  . 레이터 챠트를 통한 요소 편중도 표현

  . 활동량을 챠트로 표현


5. 알람 (모바일)

  . 일정 시간 활동이 없는 경우 알람


2 개발


1. Timeline 표현

  . 활동을 시간의 역순으로 표현


2. SNS 연동 기능 구현

  . 목표 액션 관련 데이터를 twitter facebook 공유


3 개발


1. 목표 관련 뉴스 정보 수집 기능 구현

  . 자신이 설정한 목표와 관련있는 각종 정보를 크롤링을 통해 수집


2. 멀티미디어 처리 

  . 사진 동영상 등록


4 개발


1. 소셜 기능 구현

  . 친구 맺기

  . 유사한 목표를 가진 회원을 친구로 추천

  . 목표 활동(모든 요소) 공유


5 개발


1. 소셜 기능 강화

  . 그룹 기능 구현

  . 공동 목표 관리 기능 구현

  . 관련성 있는 목표 통합 기능 구현


추가 개발


아두이노를 이용한 알람 캐릭터 인형


- 연동 가능한 캐릭터 인형

- 목표 달성을 위한 활동이 없을 경우 알람

- 시계 날씨 기본 표시

- 목표 레이터 챠트 표시



지향점


나름 적지 않은 개인 프로젝트를 진행했는데 사실상 남긴 것이 아무 것도 없다.

이는 아마도 ‘무엇을’ 구현할 것인지에만 집중한 나머지 ‘어떻게’ 구현할 것인지에 대한 

고민이 없었기 때문이라 생각한다.


‘무엇을’에 대한 고민이 깊은 경우 그 프로젝트가 성공적이라면 많은 것을 남기고

또 이후의 진행이 원활해지겠지만 실패할 경우에는 남는 것이 없다. 결과가 곧

목적이기에 결과가 않좋으면 모든 것이 안좋아지는 것이다.


하지만 ‘어떻게’에 집중한다는 것은 그 ‘과정’에 집중한다는 것이고 ‘과정’에 집중하게 되면

비록 결과가 안좋게 되는 경우라 할지라도 얻을 수 있는 것이 많다, 하다못해

문서 한쪼가리라도 얻을 것이 생긴다는 말이다.


때문에 이 프로젝트는 최대한 그 과정에서 많은 것을 남기는 것을 목표로 한다.

물론 어디까지나 개인 프로젝트이기에 가능한 일이지만…



생각하고 행동하기? 행동하고 생각하기!


이전 글에서도 언급했듯이 간간이 뭔가를 하려고 시도했고 때마다 함께 사람들을

찾아보았다. 하지만 번번이 벽에 부딪친 이유는 아이디어의 실현 가능성이 낮아서

아니 정확히 말하면 돈이 되지 않을 것이기 때문이리라.


바쁜 현대 사회에서 돈도 안되는 일에 시간을 투자하는 것은 자체로 손실이긴 하다.

하지만 개발자다. 뭐가 돈이되고 뭐가 사람들의 관심을 끌지를 제대로 알아낼 있다면

나는 개발자가 아니라 마케터나 기획자 또는 시장 분석가가 되었겠지


그렇다고 정말 모두에게 인정받을 수 있는 아이디어를 뽑아내는 일부터 하면 될까?

그렇지 않다고 생각한다. 

이리 재고 저리 재느라 아무 것도 시작을 하지 못하는 것보다는 무엇이 되었든 만들어 놓고

것을 평가하는 것이 낫다는 생각이다. 특히나 요즘 같이 개발 툴들이 좋아진 환경에서는

빠른 시간내에 prototype 만들고 평가하는 것이 가능하다.


더군다나 나같이 추상화에 약한 사람들은 구체화 된 무언가로부터 영감을 얻는 것이

훨씬 바람직한 방법이다.

그리고 앞서 말한 바와 같이 ‘어떻게’에 방점을 찍는다면 분명 많은 아이디어를

파생시킬 수 있을 것이다.


그러니 (덜떨어진)아이디어만 덜렁 들이미는 무책임한 짓거리는 하지 말자.

적어도 그럴싸한 프로토타입 하나는 만들어서 보여주는 것이 개발자의 도리이자

상대방에 대한 예의 아니겠는가.


어쨌든 나는 늦었을지라도 예의를 갖추고자 한다.


다음 포스팅에는 시스템을 만드는데 어떤 기술들을 사용하는지 간략하게 소개하고

이후 본격적인 작업 과정을 정리하도록 하겠다.



저작자 표시
신고



5년만의 개인 프로젝트를 시작하며…


지금부터 5년전인 2011년.

현재의 회사(정확하게는 2012년 1월에 현재의 회사가 창립하였다.)에 입사하면서

줄곧 같은 사업장에서 근무를 하고 있다(즉, 5년간 같은 곳에서 일하고 있다…지겹게…ㅠ.ㅠ).


2011년 당시는 내가 iOS 개발을 해보고자 전 회사를 그만 두고 잠시 프리랜서로 iOS를

개발하다가 다시 정규직으로 현재의 회사에 입사를 한 시점이다. 그래서 아직 앱 개발을 통한

대박의 꿈을 버리지 못하고 있을 때이기도 하다. 그래서 매우 열심히 개인 프로젝트를

진행하였다. 능력있는 디자이너를 만나 열심히 앱을 만들어 출시 했으나 안타깝게도

(혹은 당연하게도) 실패를 하고 말았다. 좋은 디자인에 형편없는 기능의 앱이 만들어졌기

때문이리라…


하지만 성패를 떠나 중요한 것은 그 때는 참 열심히 했다는 것이다.

새벽 6시에 출근하여 근무시간이 시작될 때까지, 그리고 점심시간, 그밖에 틈나는 시간은

모두 이 앱을 만드는데 투자했다. 그렇게 해도 피곤한 줄도 몰랐다.

그저 내가 가진 기술로 무언가를 만들어나가는 즐거움이 가득했다.



무엇이 개발자를 무기력하게 하는가?


이렇게 시작한 개인 프로젝트는 어느 순간부터 서서히 나의 시야에서 멀어져갔다.

왜그랬을까?


잠시 내 이야기에서 벗어나보자.

보통의 개발자들이 무기력하게 하루하루의 일과에 지쳐가는 모습을 많이 보게 된다.

안타깝지만 그렇게들 변해간다.

왜 그럴까?


이유야 많다.

끝없는 야근, 불합리한 진행, 낮은 보상, 낙후된 장비…


하지만 내 생각엔 뭔가 ‘재미난 일’이 없기 때문인 것 같다.

아무리 일이 지치고 함들어도 ‘재미난 일’을 통해 재충전을 할 수만 있다면

그렇게 무기력해지지는 않을 것 같다.


다시 나의 이야기로 돌아와보면, 지금도 그렇지만 당시 나의 ‘재미난 일’은 

내가 가진 기술로 무엇인가 쓸모있는 것을 만드는 일이다. 그리고 첫 2년여는

그 것이 가능했다.


현재 내가 일하는 곳은 보안이 중요한 곳이다. 그리고 해가 갈수록 이 보안은

점점 더 강력해졌다.


보안이 중요하다는 말인 즉, 내가 ‘재미난 일’을 하기 위한 리소스를 마음대로

사용할 수가 없다는 의미이다. 무언가를 하려고 하면 사방이 막혀있어 제대로

진행을 할 수 없는 상황이 되어버렸다. 결국 ‘재미난 일’을 할 수 없게 된 나는

나날이 무기력 해져 갔다. 내가 가장 필요로 하는 것들은 여전히 사용 가능하다는

것을 깨달을 때까지…



개발자는 직업적인 면에서 매우 특별한 존재다.


세상에는 매우 많은 직업이 존재한다.

하지만 그 직업들 중 자신이 직장에서 하는 일에 필요한 능력으로

‘취미’또는 ‘사업’의 영역으로 확장할 수 있는 직업은 그리 많지 않다.

적어도 ‘취미’를 삼을 수 있는 직업은 손가락으로 꼽을 정도가 아닐까?

(취미가 직업이 된 경우는 좀 빼자…-.-)


아주 바람직한 직업이다.

일하다 알게 된 것으로 취미 생활을 완성할 수도 있고,

취미 생활을 하다가 얻은 지식으로 생산성을 높일 수도 있다.

나는 이런 이점을 충분히 누리고자 한다.

다행히 나는 단지 생계 수단으로 이 직업을 선택하지는 않았다.

이 직업에서 나의 즐거움을 충족시켜주는 많은 요소들을 보았기에

선택을 하였고, 아직까지는 그 선택이 유효하다.

그리고 이제 그 선택이 주는 혜택을 다시 한 번 누려보고자 한다.


Till60를 시작하며


사실 그 사이에 아무것도 없었던 것은 아니다.

2015년에 Springboot와 JPA 그리고 AngularJS와 Bootstrap을 공부해보고자

웹 시스템을 하나 만들기 시작했다. 컨셉은 프로젝트 관리(너무 식상한가?)


내 생각은 이랬다.

개발자에게 문서작업이 많은 이유는 관리자들이 개발자들이 하는 일을 잘 모르기

때문이다. 관리자들이 개발자들이 하는 일을 잘 모르는 경우 개발자에게는

상당한 인터럽트가 걸리게 마련이다. 이미 세상에 좋은 프로젝트 관리 툴 또는

시스템이 많음에도 불구하고 이러한 부분은 개선되지 않고 있다.


이는 프로젝트 관리 툴이나 시스템이 주로 개발자 위주로 만들어졌기 때문이라

생각한다. 그래서 나는 개발자들과 관리자들이 모두 부담없이 사용할 수 있는

시스템이 필요하다고 생각했다. 개발자들은 개발자들 대로 업무에 필요한

내용들을 관리할 수 있고 시스템은 이렇게 만들어지 개발자들의 업무 내용들을

‘관리자의 구미에 맞게’변형하여 관리자들에게 보여주는 것이다.

좀 더 쉽게 말하자면 reporting 기능이 강화된 프로젝트 관리 시스템이라고나 할까?


현재는 멈춰있지만 이 프로젝트는 아직도 진행형이다.

(그래도 이 프로젝트를 모태로 업무에 사용 중인 간단한 시스템 2개를 만들었으니

나름의 역할은 다한 것 아닐까^^?)


이후 이렇다할 개인 프로젝트가 없다가 얼마전 문득 너무 매너리즘에 빠진

내 자신을 발견했다. 그래도 잠시 아두이노를 통해 기력을 되찾고 있던 차라

급속도로 새로운 의지를 다잡을 수 있었다.


처음 구상은 이랬다.

컨셉은 명확하다. 


“60살이 될 때까지는 내가 만족할만한 ‘무언가’를 만들자!”


이 컨셉으로 처음에는 사내 동호회를 하나 만들어볼까 했다.

단일한 목적이 아닌 서로 각자의 목적을 이루기 위해 정보를 교환하고

서로간에 자극이 될 수 있도록 노력하는 모습을 보여줄 수 있는…

하지만 명확한 컨셉에 비해 동호회에 대한 구상은 너무나 허술해서

실현 가능성이 없어보였다.


그리고 이런 과정에서 차라리 이러한 컨셉을 시스템으로 만들어보면

어떨까 하는 생각이 든 것이다.


그리고 이 시스템에 직접적인 영감을 준 것이 지금 이 글을 쓰고 있는

Scrivener라는 툴이다. 간단하게 말하면 Scrivener는 뭉뚱그려 ‘글’이라는 것을

작성하는 툴이 아니라 글을 구성하고 있는 많은 요소들을 별도로 관리할 수

있도록 해주는 툴이다. (보다 상세한 것은 Scrivener로 검색해보시길)


Till60도 그러하다.

내가 무엇을 할 것인지 목표를 정하고 그냥 뭉뚱그려서 ‘무엇을 했는가’로

마치는 것이 아니라 보다 구체적이고 명확하게 ‘목표’를 위해 필요한

요소들을 구분해내고 그 각각의 요소들을 어떻게 채워 나가느냐에 초점을

맞출 예정이다. 단기적인 To-Do가 아닌 중장기 목표 달성을 위한 시스템

이라고나 할까?


보다 자세한 내용은 다음 포스팅에서 언급하겠다.



기대 반 우려 반


사실 시작하기도 전에 상당히 걱정이 되었다.

또 여느 때와 같이 용두사미가 되면 어찌할까…

그리고 그러한 위험을 막기 위해 같이 할 동료를 구해보았지만 사람들의

관심을 끌기에는 역부족이었다.


결국 혼자 시작을 하게 되었는데…역시나 우려가 현실로 나타날 조짐을

보였다. 애초의 계획대로라면 이 글은 적어도 3주 전에는 쓰여졌어야 한다…ㅠ.ㅠ


앞으로의 숙제는 얼마나 꾸준함을 유지하느냐 이다.

부디 60살이 되기 전까지는 뭐 한가지는 남겨보자…ㅠ.ㅠ

  


저작자 표시
신고

+ Recent posts

티스토리 툴바