루비 시작하기

자바스크립트 공부를 하며 Node.js 백엔드 개발을 경험해오며 개발자로 성장하기 위해 달려왔다. 면접을 보며 입사하기로 하게 된 기업에서 자바스크립트 스택을 보고 지원했는데 루비 온 레일스를 사용하는 기업이였고 그에 따라 새로운 언어를 배워야 하는 상황이다. 학교에서 자바를 잠깐 배운것 외에는 자바스크립트 외의 언어를 경험해보지 못했는데 새로운 언어와 프레임워크를 경험하게 되어 좋은 경험이 될것 같다는 생각이 든다.😂

📩 Ruby Git Repo

루비는 어떤 언어인가?

루비를 공부 해봐야겠다고 생각한 후 루비는 어떤 언어인가를 가장 먼저 알아 보게 되었다. 루비 홈페이지를 찾아보니 루비에 대해 다음과 같이 설명해 주고 있었다.

  1. 루비는 순수 객체 지향 언어이다.
  2. 루비의 모든 것은 객체로 분류된다.
  3. 루비는 유연한 언어이다.
  4. 다른 객체 지향 언어와 달리 의도적인 단일 상속만을 제공한다. 대신 모듈 기능을 이용하여 필요한 메서드를 사용할 수 있다.

루비는 모든 것을 객체로 분류한다는 특징이 가장 생소하지만 흥미롭게 다가왔다. 자바스크립트 처럼 원시타입과 참조타입을 분류하지 않고 모든것을 객체로 분류한다는 것이 새로운 언어를 배우기 시작하는 단계에서 흥미를 불러와 주었다.

그렇다면 왜 루비인가

왜 루비를 사용하는지 궁금했다. 웹개발이라 하면 자바스크립트, 파이썬, 자바 3가지를 생각하고 루비라는 언어를 들어만 봤지 실질적으로 접하는 기회가 없었기 때문이다.
루비를 사용하여 웹 개발을 진행 할 때 루비 온 레일스라는 프레임워크를 사용한다고 한다.
루비를 사용하는 가장 보편적인 이유는 쉽고 개발 생산성이 빠르다. 라고 많이 얘기를 하는 것 같다. 아직 루비 기본 문법을 보며 따라하는 단계에서는 느끼지 못했지만
Express를 사용하여 개발을 할때의 장점과 비슷한 느낌이지 않을까 넘겨짚어 생각하게 된다. 왜 루비를 사용하는지 회사에 물어보면 그럴듯한 답변이 올지 궁금한데 사실 못 물어 보겠다….

자세히 보기

javascript-생성자 함수를 사용하여 객체 생성하기

생성자 함수에 대한 객체 생성

생성자 함수를 사용하여 객체를 생성 방식에는 Object 생성자 함수를 사용하는 방법이 있다.

Object 생성자 함수를 사용하는 방법

new 연산자와 함께 Object 생성자 함수를 호출하여 빈 객체를 생성한다.
이때 객체를 생성하고 프로퍼티나 메서드를 추가하여 객체를 완성시키면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
const person = new Object();

// new Object 함수를 호출하면 빈객체가 생성된다.
console.log(person); // {}

// 빈객체에 프로퍼티를 추가한다.
person.name = 'hanjuren';
person.getName = function () {
console.log(`Hello My Name is ${this.name}`);
};

console.log(person); // { name: 'hanjuren', getName: f }
console.log(person.getName()); // Hello My Name is hanjuren

생성자 함수에 의해 생성된 객체를 인스턴스라고 부른다.

생성자 함수의 종류는 다음과 같다.

  1. String
  2. Number
  3. Boolean
  4. Function
  5. Array
  6. Date
  7. RegExp
  8. Promise

생성자 함수를 호출하여 객체를 생성하는 것은 객체 리터럴을 사용하여 생성하는 것보다는 비효율적이므로 필요한 상황이 아니라면 바람직 한 생성방식은 아니다.

자세히 보기

아파트 온도, 습도, 전력 실시간 데이터 관리 프로젝트 마무리하며.

아파트 실시간 데이터 관리 프로젝트를 마무리하며 느꼈던점

Node.js를 기반으로한 협업을 통해? 사실 현업에 계신 분 2명과 취준생 2명이 모인 스터디라 현업 개발자 분들 께서 많은 정보와 팁을 알려주신 재능기부 현장느낌이였다. 하지마 어디서도 들을 수 없는… 그런 정보들을 얻는 기회였다고 생각한다. 물론 프로젝트를 그분들께 의존하지는 않았다. 기본적인 세팅과 아이디어를 제공해주시고 거의 2명이 만든 그런 느낌이였다.

Mqtt라는 통신기법에 대해 처음 알게되었고 어떤 기능을 위해 여러가지 고려하여 다양한 선택을 하는 생각의 폭을 넓힐 수 있는 좋은 경험으로 생각된다. 무턱대고 기능을 위해 내가 아는 것만 활용하여 물론 아는것이 많지도 않다. 하지만 틀에 갖혀서 개발하는 것보다 기능을 위해 많은 것을 생각하고 고려하면 또다른 방향으로도 더 좋은 결과를 낳을 수 있다는 것을 느끼는 프로젝트 였다.

또한 과연 내가 백엔드 개발자를 꿈꾸지만 그에 맞는 준비를 하고 있었는가 그냥 무턱대고 코드만 치며 내것이 되었다라고 생각하던 것은 아니였을까 라는 의문을 나에게 던지는 값진 시간이 되었다.

좋은 결과물을 위해서는 많은 공부와 시간을 투자할 준비가 되어있어야 한다. 새로운 것에 대한 도전 그리고 알아가기 위해 노력하는 자세 또 그것을 내 것으로 만들 준비 이러한 덕목이 앞으로 개발자가 되기 위해 내가 준비하는 과정에서 가장 중요하지 않을까 라는 생각이 들었던 프로젝트였다.

지난 프로젝트들을 정리하며 그때 내가 생각했던것을 정리하고 다시 생각을 해보며 그때 생각한 것을 나는 지키고 있는가. 모든 다짐을 지키지는 못했지만 이때 다짐했던 하나의 결과를 위해 고민을 수없이 하고 의문을 가지고 기능 구현에 안주하지 않는 자세를 지금까지 갖고 있었구나 라는 생각을 하게 된다. 어쩌면 프로젝트를 진행하는 과정에서 사용하는 기술, 언어, 모듈에 대한 이해도 모두 중요하지만 이러한 과정에서 나를 발전시킨 것이 아니였을까. 또 아직 더 발전해야 하는 나의 모습을 더욱 앞으로 나아가게 하는 과정이라고 생각된다.

아파트 온도, 습도, 전력 실시간 데이터 관리 프로젝트 Part 2.

스케줄러를 통한 이메일 보내기 기능 구현

사용자의 실시간 데이터를 서버로 전송받고 데이터베이스에 저장하여 쌓인 데이터를 연산하여 사용자에게 특정한 일자에 보내도록 하는 기능을 제공하기로 했다.

가장 먼저 생각한 방식이자 이상적인 방법이였던 카카오톡으로 전송하기는 토이 프로젝트이기에 사업자 번호 등 카카오에서 요구하는 조건에 부딧혀 포기하고 구글 이메일 보내기로 방향을 틀게 되었다.

구상하는 방식은 이렇다.

  1. 매월 1일 자정에 모든 동 호수의 데이터를 그래프로 그린다.
  2. 각 호수별 사용자이자 입주민이라는 가정하에 그래프 이미지를 이메일로 매월 1일 00시 15분에 발송한다.

스케줄러 활용

우리는 node-schedule모듈을 활용하여 스케줄러를 작성하여 메일을 발송하기로 했다.

  1. 그래프 이미지 그리기
  • 모든 집의 데이터를 각각 그래프로 그려 이미지로 파일로 저장
그래프 그리기
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
const get_month = () => {
const today = new Date();
return today.getMonth() + 1;
}

// 아파트 단지, 동, 호 일별 데이터 가져오기
const sensorData = async (Complex, Dong, Ho) => {
let exData = await apt_Info.sensorFind(Complex, Dong, Ho);
return exData;
};

// 아파트의 모든 단지 동 호 정보 가져오기
const basename = async () => {
const aptInfo = await apt_Info.aptFind();

for(let i=0; i < aptInfo.length; i++) {
// 파일 이름 지정 => ex) 단지 동 호.png
let fileName = `${aptInfo[i].AptDong.apt_complex}${aptInfo[i].AptDong.apt_dong}${aptInfo[i].apt_ho}`;
// 단지, 동, 호의 센서 데이터 받아오기.
let data = await sensorData(aptInfo[i].AptDong.apt_complex, aptInfo[i].AptDong.apt_dong, aptInfo[i].apt_ho);

// 차트를 그리기위한 날짜, 데이터 별 배열 분리
let dateArray = [];
let humiArray = [];
let tempArray = [];
let wattArray = [];
data.map((sensor) => {
let newDate = new Date(sensor.dataValues.date);
dateArray.push(dateAndTime.format(newDate, 'MM-DD'));
tempArray.push(sensor.dataValues.humidityAVG);
humiArray.push(sensor.dataValues.temperatureAVG);
wattArray.push(sensor.dataValues.electricitySUM);
});

// 차트 그리기 함수로 파일 이름과 데이터 배열 전달
humiChart(fileName, humiArray, dateArray);
tempChart(fileName, tempArray, dateArray);
wattChart(fileName, wattArray, dateArray);
};
console.log("차트 그리기 시작");
logger.info('create chart');
};

// 아파트 모든 세대의 전력 차트 그리기
const wattChart = (fileName, data, date) => {
const filewatt = fileName + "watt.png";
saveChart(filewatt, "Watt", data, date);
};

// 아파트 모든 세대 온도 차트 그리기
const tempChart = (fileName, data, date) => {
const filetemp = fileName + "temp.png";
saveChart(filetemp, "Temp", data, date);
};

// 아파트 모든 세대 습도 차트 그리기
const humiChart = (fileName, data, date) => {
const filehumi = fileName + "humi.png";
saveChart(filehumi, "Humi", data, date);
};

//차트그리기 스케줄러
const drawChart = () => {
// 매달 자정에 파일 생성
const jobs = schedule.scheduleJob('0 0 01 * *', function() {
basename();
});
};

이미지 그리기 코드

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const ChartJsImage = require('chartjs-to-image');
const fs = require('fs');

const chart = new ChartJsImage();

const days = function(month,year) {
return new Date(year, month, 0).getDate();
};

const get_Month = () => {
const today = new Date();

return today.getMonth() + 1;
}

const makeFolder = (dir) => {
try {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
}
} catch (err) {
console.error(err)
}
}

const saveChart = async (filename, type, data, date) => {
// 차트 label 지정
const labels = date;
// 차트 그리기
chart.setConfig({
type: 'line',
data: { labels: labels, datasets: [{ label: type, data }] },
});

// 월별 / 데이터별 파일 구분하기
const folderName = './data/' + (get_Month() - 1);
const monthPath = folderName + '/' + type;
// Write file to disk
makeFolder(folderName);
makeFolder(monthPath);
await chart.toFile(monthPath + "/" + filename);
}

module.exports = saveChart;

각각의 파일은 월별 / 데이터 종류로 구분되어 저장되고 저장된 이미지를 사용자에게 전송한다.

  1. 이메일 보내기
이메일 보내기
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
29
30
31
32
33
34
35
// 이메일 보내기 스케줄러 시간 지정 
const mailResult = async () => {
const userinfo = await User.findAll({
attributes: ['uemail', 'apt_ho'],
include: {
model: AptHo,
include: {
model: AptDong,
}
},
});
userinfo.map((user) => {
let emailParam = {
toEmail: `${user.uemail}`,
subject: `${get_month() -1}월 사용량입니다.`,
text: `${get_month() - 1}월 사용량입니다.`,
// ex)1단지101동101호
name: `${user.AptHo.AptDong.apt_complex}${user.AptHo.AptDong.apt_dong}${user.AptHo.apt_ho}`,
month: get_month() - 1,
};

// const rule = new schedule.RecurrenceRule();
// const m = 50;
// rule.minute = m;

// 매달 1일 0시 15분 이메일 보내기 실행
const j = schedule.scheduleJob('13 13 02 * *', function() {
// const j = schedule.scheduleJob(rule, async function() {
console.log("send mail");
// await basename();
logger.info('send mail');
mailSender.sendGmail(emailParam);
});
});
};

테스트를 위해 시간을 조정하여 진행하였고 스케줄러 시간 부분만 원하는 시간으로 조정하면 정상적으로 전송이 된다.

결과



아파트 온도, 습도, 전력 실시간 데이터 관리 프로젝트 Part 1.

아파트 실시간 데이터 관리 프로젝트

아파트 실시간 데이터를 전송받아 저장하고 사용자에게 데이터를 제공하는 서비스를 만들어보았다.
Node.js, express를 기반으로 하여 서버를 구성하고 사용자가 데이터를 볼 수 있는 View는 기본적인 html로 구성하여 백엔드 구축을 중점으로 한 프로젝트이다.

실시간 데이터를 전송받기 위해 선택한 통신방법은 MQTT통신을 사용하였다.
소켓 통신을 통해 실시간 데이터 처리를 하려했던 과정에서 MQTt통신으로 방법을 변경하게 된 이유는 다음과 같은 이유였다.

  1. Socket 과 Mqtt 통신 모두 실시간으로 데이터를 전송 할 수 있지만 Socket은 데이터의 전송을 하고 응답을 기다리고 있다.
    하지만 우리의 프로젝트는 실시간 데이터를 전송만 받을 뿐 다시 응답을 돌려 주지 않기 때문에 필요없는 자원이 소모된다. 그러나 Mqtt통신은 데이터의 전송을 하지만 응답을 대기하지 않는다.
  2. 실시간 통신을 위한 서버와의 연결이 비정상적으로 해제 되었을 때 Socket은 재 연결 까지 전송 받아야 하는 데이터가 유실된다. 반면 Mqtt통신은 연결이 해제 되어도 데이터를 연결이 될 때까지 보관 후 연결시 순차적으로 전송해주기 때문에 유실 가능성이 적다.
  3. 프로젝트에서 가공하는 데이터가 온도, 습도, 전력 과 같은 데이터이기 때문에 아두이노 같은 IOT기기에 적합한 통신 방법을 사용해 보기 위해서

그렇다면 WebSocket과 Mqtt는 무엇이 다른가???

  1. WebSocket이란 TCP기반 소켓 통신을 대체할 목적에서 등장한 양방향 통신기법이다.
  2. Mqtt란 저전력, 신뢰할 수 없는 네트워크 등의 상황에서 사용하는 메시징 프로토콜이다.

두가지 모두 실시간 통신이 가능하지만 두 방식을 직접 적으로 비교할 수는 없다고 한다. 이유를 알아보니 통신 레벨의 차이와 mqtt는 통신 프로토콜에 의존하지 않으며 패킷 구조로 데이터를 전송하는 차이점이 있다. 간단하게 두가지의 차이점을 알아보고 우리는 왜 Mqtt를 선택하여 실시간 온도 등의 데이터를 전송받기로 했는가에 대한 이유를 알아보자.

자세히 보기

SQLD 정규화

정규화

정규화의 가장 쉬운 의미는 데이터 베이스 수행에 있어 성능 향상 전략중에 한가지이다.

데이터 중복제거와 분류를 통해서 입력/수정/삭제 성능을 향상시켜준다. 하지만 계속되는 엔터티의 생성으로 조인이 빈번하게 일어나 데이터 조회 성능은 저하 될수도 있다.

가장 이해하기 쉬운 의미..

  1. 1정규화 : 모든 속성은 하나의 값을 가져야 한다.(반복적이고 같은 의미를 담는 형태가 있어서는 안된다.)
  2. 2정규화 : 모든 속성은 기본키에 종속 되어야 한다.
  3. 3정규화 : 기본키가 아닌 모든 속성간에 서로를 종속 할 수 없다.

예를 들어보자…

주문 테이블
주문번호 (PK)
주문일자
품목코드
품목단가
주문수량
고객번호
고객명

주문이라는 테이블에 주문에 대한 모든 데이터가 들어가있다. 예를 들어 내가 옷 두개를 한번에 주문한다. 그렇다면 데이터는 다음과 같이 저장이 될것이다.

주문번호 주문일자 품목코드 품목단가 주문수량 고객번호 고객명
1 10/17 1 2000 1 1 한주련
1 10/17 2 3000 1 1 한주련

1번이라는 주문번호로 주문한 상품의 수만큼 중복된 컬럼이 존재 하게 될것이다. 이 구조에서는 1정규화가 필요하다. 1번이라는 주문번호가 중복되지 않도록…

주문
주문 번호 (PK)
주문일자
고객번호
고객명
주문품목
주문번호 (FK)
품목코드
품목단가
주문수량

1차 정규화의 결과로 이제 1번이라는 하나의 기본키로 여러개의 상품을 중복없이 식별할 수 있다.

2차 정규화는 주문품목 테이블에서 필요성이 나타난다. 2차 정규화란 복합키로 구성된 (여러개의 PK) 경우 2차 정규화의 대상이 된다 이는 복합키의 일부에만 종속되는 속성이 있을 경우 이 속성을 분리해주는 것이다.

1차 정규화를 마친 주문 품목 테이블에서 품목단가라는 속성은 품목코드라는 키와만 관련이 있고 주문번호와는 관련이 없다 이때 품목단가 속성이 일부 키에만 종속되어 있으므로 해당 속성을 분리해주면 된다.

주문품목
주문번호 (FK)
품목코드 (FK)
주문수량
품목
품목코드 (PK)
품목 단가

2차 정규화를 통해 일부의 종속성을 가진 속성을 분리 해주었다.

마지막 3차 정규화는 일반 속성인 컬럼은 기본키에 의존해야 하는데 일반 속성에 의존하고 있는 속성들을 분리하는 것이다.

주문테이블을 살펴보면 고객명이라는 속성은 기본키인 주문 번호에 종속성을 가지고 있지 않고 고객번호 속성에 종속성을 가지고 있는 상태이다. 따라서 3차 정규화의 대상이 된다.

주문
주문번호 (PK)
주문일자
고객번호 (FK)
화원
회원번호 (PK)
고객명

솔직히 그동안 데이터베이스 설계하면서 정규화에대한 개념을 모르고 한번에 이과정을 수행했는데 그럼 된거 아닌가 싶지만… 시험을 보기위해서 과정을 나열하다보니 내가 해온 과정과 비슷하지만 다른.. 어떤 그런 어려운 느낌…

SQLD 데이터 모델링

데이터 모델링이란?

  • 정보시스템을 구축하기 위한 데이터 관점의 업무 분석 기법
  • 데이터베이스를 구축하기 위한 분석/설계의 과정

모델링

  • 복잡하고 다향한 현상을 표기법에 의해 규칙을 가지고 표기하는 것을 의미한다.
  • 가설적 또는 일정 양식에 맟춘 표현
  • 어떤 것에 대한 에비표현으로 그로부터 최종대상이 구축되도록 하는 계획으로서 기여 하는 것

모델링의 특징

모델링은 추상화, 단순화, 명확화 3가지 특징이 있다.

  1. 추상화는 현실세계를 일정한 형식에 맟추어 표현을 한다는 의미이다.
  2. 단순화는 복잡한 현실세계를 약속된 규약에 의해 제한된 표기법, 언어로 표현하여 쉽게 이해할 수 있도록 하는 개념을 의미한다.
  3. 명확화는 누구나 이해하기 쉽게 대상에 대한 애매모호함을 제거하고 정확하게 표기하는 것을 의미한다.

모델링의 세가지 관점

  1. 데이터 관점 : 업무가 어떤 데이터와 관련이 있는지 또는 데이터간의 관계는 무엇인지에 대해 모델링 하는 방법
  2. 프로세스 관점 : 업무가 실제하고 있는 일은 무엇인지 또는 무엇을 해야 하는지를 모델링 하는 방법
  3. 데이터와 프로세스의 상관관점 : 업무가 처리하고 있는 일의 방법에 따라 데이터는 어떻게 영향을 받고 있는지 모델링 하는 방법

데이터 모델이 제공하는 기능

  1. 시스템을 현재 또는 원하는 모습으로 가시화하도록 도와준다.
  2. 시스템의 구조와 행동을 명세화 할 수 있게 한다.
  3. 시슽템을 구축하는 구조화된 틀을 제공한다.
  4. 시스템을 구축하는 과정에서 결정한 것을 문서화 한다.
  5. 다양한 영역에 집중하기 위해 다른 영역의 세부 사항은 숨기는 다양한 관점을 제공한다.

중요성 및 유의점

  1. 파급효과 : 시스템 구축이 완성되어 가는 과정에서 수많은 단위 테스트가 수행되고 이러한 과정이 반복된다. 이러한 테스트 과정에서 데이터 모델이 변경되는 상황은 프로젝트의 규모가 클수록 문제가 일어난다. 이러한 이유로 데이터 설계는 중요하다.
  2. 복잡한 정보 요구사항의 간결한 표현 : 데이터 모델은 정보요구사항을 파악하기 위해 유용하다.
  3. 데이터 품질 : 데이터로 이용할 수 있는 비즈니스 기회를 얻기 위해 데이터는 필요한 데이터만이 존재 해야 한다.

데이터 모델링의 3단계 진행

데이터 모델링 내용 수준
개념적 데이터 모델링 추상화 수준이 높고 업무 중심적이며 포괄적인 수준의 모델링 추상적
논리적 데이터 모델링 시스템으로 구축하고자 하는 업무에 대하여 key 속성 관계 등을 정확하게 표현
물리적 데이터 모델링 실제로 데이터 베이스에 이식할 수 있도록 설계 구체적

SQLD 속성

속성이란 업무에서 필요로 하고 인스턴스에서 관리하고자 하는 의미상 더이상 분리되지 않는 최소의 데이터 단위이다.

속성의 개념은 다음과 같다.

  • 업무에서 필요로 한다.
  • 의미상 더이상 분리 되지 않는다.
  • 엔터티를 설명하고 인스턴스의 구성요소가 된다.

엔터티와 인스턴스, 속성, 속성값의 관계

  1. 하나의 엔터티는 두개 이상의 속성을 갖는다.
  2. 하나의 엔터티는 두개 이상의 인스턴스의 집합니다.
  3. 하나의 속성은 하나의 속성값을 가진다.

속성의 특징

  1. 업무에서 필요로 하는 정보이다.
  2. 정규화 이론에 의해 정해진 식별자에 함수적 종속성을 가진다.
  3. 하나의 속성에는 한개의 값만을 가지게 해야한다. 하나 이상의 값이 필요하다면 별도의 엔터티로 분리를 하는 것이 좋다.

속성의 분류

  1. 속성에 따른 분류
  • 기본 속성 : 업무로부터 추출한 모든 속성이 여기에 해당된다.
  • 설게 속성 : 업무상 필요한 속성 이외에 데이터 모델링을 위해 업무의 규칙화를 위해 속성을 새로 만들거나 변형하여 정의하는 속성.
  • 파생 속성 : 다른 속성에 의해 영향을 받아 생성되며 보통 계산된 값으로 쓰이는 경우가 많다.
  1. 엔터티 구성 방식
    엔터티를 구별하기 위해 주 식별자로 사용하는 속성을 PK 속성, 다른 엔터티와 관계를 포함한 속성을 FK 속성 나머지 속성을 일반 속성으로 구별한다.

도메인

각 속성이 가질 수 있는 범위를 도메인이라고 하는데 쉽게 이해하기 위해서 속성에 대한 값의 범위, 데이터 타입, 크기, 제약사항을 의미한다.

속성의 명명

  1. 엔터티와 마찬가지로 현업에서 사용하는 이름을 사용한다.
  2. 약어 사용은 자제한다.
  3. 서술식 표현은 자제하며 명사를 사용한다.
  4. 유일한 속성 이름을 지정한다. 이는 반 정규화 적용시 안정적 적용이 가능한 장점을 가진다.