주니어 메이커들

주니어 메이커들

주니어 메이커들이 매주 1회씩, 이번 주에 만든 것에 대해 가볍게 글을 남기는 클럽입니다.

공개 54 멤버

가이드라인

["개발 혹은 디자인을 공부하는 학생 및 취준생, 그리고 2년 미만의 개발자와 디자이너만 참여할 수 있습니다.","매주 자신이 한 것을 아래 질문을 참고해서 가볍게 남깁니다.<br><br>1. 이번 주에는 무엇을 만들었는지?<br>2. 만들면서 뭐가 어려웠는지?<br>3. 어떻게 해결 중인지(해결했는지)?<br>4. 다음 주는 무엇을 만들 예정인지?<br><br>","특히 아래 메이커 분들 대환영이에요. 글쓰기와 팀 찾는 것 열심히 도와드릴게요 :)<br><br>- 개인 블로그에 쓰는 대신 더 많은 사람들과 연결되고 소통하고 싶은 분들<br>- 사이드 프로젝트를 하고 계신 분들<br>- 초기 스타트업 합류에 관심이 많은 분들 "]

맨듀

맨듀

flutter로 클론코딩 시작 전 Dart 이해하기

개발자가 되고 말거야!를 외쳤지만 계속 붕 떠다니고만 있습니다. 이것저것 하고는 있는데 말만 하고 있는 것 같네요.
창업 부트캠프 멤버분 중 한분이 앱개발 스터디원을 모집하신다고 하셔서 아~무것도 할 줄 모르는 제가 마음만 들고 참여했습니다.

클론코딩을 하기로 했고 먼저 Dart에 대해 이해하는 것이 좋다고 하셔서 강의를 듣고 있어요.

Dart 공부부터 클론 코딩하는 과정까지 지켜봐주세요!

강의 : https://nomadcoders.co/dart-for-beginners (노마드코더 Dart 시작하기)

# 1.The Var Keyword
1) var 키워드 사용

함수나 메소드 내부에 지역변수 선언 할 때

​2) 명시적 타입지정

class에서 변수나 property를 선언 할 때

​

함수나 메소드 안에서 지역변수를 사용한다면 var를 사용. 컴파일러가 타입을 인지하고 있기 때문에 일일이 타입을 지정하지 않아도 된다.

​

변수 수정시 타입을 지키세요! var 사용이 가장 권장된다.

image.png

#1.2 Dynamic Type
여러가지 타입을 가질 수 있는 변수에 사용하는 키워드.

타입을 지정하면 dynamic 안에서는 타입을 알 수 있지만 밖에서는 알 수 없음. 지정한대로.

항상 써야 할 필요는 없다. 필요한 때에만 사용.

image.png

#1.3 Nullable Variables

Null safety는 개발자가 null값을 참조할 수 없도록 하는 것. null 값을 참조하면 런타임 에러가 뜸.

런타임 에러는 사용자가 앱을 사용하는 중에 에러가 뜬 다는 것. 컴파일 전에 에러를 찾는 것이 중요한데 그게 바로 null safety가 한다.

​

null safety가 없는 코드. string length가 0인지 아닌지 판별하는 함수.

image.png

string을 보내야하는 곳에 null을 보냈기 때문에 런타임 에러가 난다. 사용자의 기기에서!

null을 삭제하는 것은 좋지 않다. null 상태도 가질 수 있어야함. 문제는 참조할 때 발생.

​

dart에서는 어떤 변수가 null이 될 수 있음을 정확히 표시해야 한다.

​

예시) 이렇게 하면 안됨. nico는 오직 String이어야 함.

image.png

이 경우에 nico가 null,String 모두 되게 하려면

image.png

물음표를 붙여주면된다. string ?(or) null의 의미가 된다. 모든 변수는 non-nullable.

​

#1.4 Final Variables

변수 선언하면 수정 가능한 변수가 만들어지는데 변경할 수 없게 하려면 final을 선언.

javascript나 typescripte의 const와 같다.

image.png

#1.5 Late Variables

late는 final이나 var 앞에 붙여줄 수 있는 수식어다. 초기 데이터 없이 변수를 선언 할 수 있게 해준다.

필요한 데이터가 없을 수 있으니 데이터 없이 변수를 생성하고 나중에(late) 받는 것.

image.png

final변수이니 변수를 또 만들 수 없다.

image.png

이렇게 출력하려고 하면 할당 받지 않았기 때문에 dart가 막아준다.

flutter에서 api와 작업할 때 많이 보게 될 것. late 변수를 만들고 api 요청을 보낸 후 api에서 값을 보내주면 그걸 late 변수에 넣어준다.

​

#1.6 Constant Variables

javascript나 typescript와는 다르다. javascript, typescript의 const는 final과 비슷하다.

image.png

final과 똑같이 동작한다. 수정 안됨.

! 중요한 건 const는 compile-time에 알고 있는 값이어야 한다는 것.

예를 들어 api 키가 있다면, const에 넣어주면 절대 안바뀔거고 컴파일이 될 때 그 값을 알고 있을거야.

API 요청을 한다고 가정해보면 / fetchApi , 컴파일러는 api의 변수값 모른다.

> 왜냐면 api에서 불러와야 하니까 >> 그건 final !

앱스토어에 앱을 올리기 전에 알고 있는 값이라는 것. 값을 알고 있다면 const ,

어떤 값인지 모르고 그 값이 api로부터 오거나 사용자가 입력해야하는 거라면 final이나 var이 되어야 한다.

​

#1.7 Recap

복습하기! 복습 영상 보며 위 내용 추가 및 정리하기!

3
1
탕라마

탕라마

출시를 앞둔 PM의 노가다 작업

안녕하세요! 다들 연휴를 어떻게 보내셨나요?

저는 노가다 손품을 열심히 팔았답니다.

출시를 앞둔 비건 맛집앱에 가게 데이터를 심는 작업을 하고 있어요.

유저가 함께 가게를 등록하며 맛집 지도를 만들어가는 게 저희 서비스의 컨셉이에요!

그렇지만 앱을 다운받았는데 휑-한 지도를 맞닥뜨리면,,

재접속 할 유저가 많지 않을 것 같아 초기 데이터를 1,000개 정도 심으려고 해요.

비건 맛집 리스트는 전국에 있는 친구/단체들에게 협력을 요청했어요.

전국 곳곳에서 기존 지도앱을 활용하여 지역 비건 지도를 운영하고 있거든요 ㅎㅎ

image.png

현재까지 서울`경기, 전주, 대전, 부산 지역의 데이터를 확보했어요.

그 중 부산 지역은 제가 운영하고 있어요 ✌

저희 팀의 똑똑한 백엔드 개발자에게 카카오맵의 링크를 주니

필요한 데이터를 크롤링해줬어요.

이렇게요!

image.png

덕분에 [가게명, 주소, 그리고 비건이 가능한 메뉴명과 요청방법] 데이터를 쉽게 추출했어요!

하지만 서비스에 등록하기 위해서는 가게 기본 정보와 비건 메뉴 정보를 더 채워야해요.

특히, 비건 메뉴 정보는 불완전한 데이터가 많아서 더 보충해야해요.

  1. 가게 기본 정보: (가게명, 주소) + 좌표, 전화번호, 홈페이지, 카테고리

  2. 비건 메뉴 정보: 가게의 비건 타입, 비건이 가능한 메뉴명, 메뉴의 가격, (해당하는 경우) 비건으로 요청하는 방법

필요한 데이터를 채우기 위해 열심히 네이버에 검색했어요.

그리고 약 6시간만에 전주`전북의 가게 데이터 150개를 완성했어요

이렇게요!

image.png(좌표는 프론트 개발자가 카카오 api를 활용하여 해결해줬어요. 원래는 구글 스프레드시트의 응용 프로그램을 활용하려고 했는데, 소수점이 5자 정도 짧아서 엉뚱한 위치에 마커가 찍히더라구요)

검색하면서 더더욱

  • '한국에서 비건으로 먹고 살기 힘들다(◜◡◝) (외식을 하기 위한 정보를 찾는 게 너무 '힘들어서'요 ㅠㅠ)'와 동시에

  • '맛있어보이는 가게가 이렇게 많다니! 비건이라서 행복해..(*´∪`)'

를 느끼는 시간이었습니다.

tmi. 저만 배고플 수 없으니(^^) 맛있어보이는 가게들을 인스타그램 스토리로 막 올렸어요. 그랬더니 4명이 전주행 티켓을 예약했다고..



한국에서 비건을 지향하시는 분들이 쉽고, 맛있고, 즐겁게 신념을 추구하는 데 저희 어플이 도움이 되면 좋겠어요!!

내일은 앰플리튜드 대시보드를 구축하고, 약관을 마지막으로 검토할 예정입니다.

남은 한 주도 함께 파이팅해요🚀

5
1
문지웅

문지웅

Next.js로 구현해 본 LinkTree

우리가 만들게 될 결과물은 아래와 같습니다.

screely-1696143805516.png

1. 프로젝트 준비 및 생성

준비물: 프로필 이미지- 프로필 이미지로 사용할 이미지 파일 또는 주소가 필요합니다.

Next.js를 베이스로 만들 예정이므로 아래 명령어로 프로젝트를 생성합니다.

npx create-next-app@latest

## 2. 프로젝트 구현

이제 컴포넌트들을 구현하면 됩니다.

( ) 안의 내용은 제가 구현한 컴포넌트 이름들입니다. 😊

- 전체 컴포넌트들을 포함할 레이아웃 컴포넌트( ProfileCard.tsx )

- 프로필 이미지와 이름, 직업을 표시할 컴포넌트(UserInfo.tsx)

- 이미지 컴포넌트 (ProfileImage.tsx)

- 공유하려는 링크들을 표시할 컴포넌트(UserLinks.tsx)

- 각 링크에 대한 컴포넌트(LinkItem.tsx)

- 소셜 아이콘 모음 컴포넌트(SocialIcons.tsx)

- 각 아이콘에 대한 컴포넌트(LinkIcon.tsx)

import ProfileCard from "@/components/ProfileCard";

const USER_NAME: string = "woongsnote";

export default function Home() {

  return (
    <>
      <main className="flex h-screen flex-col items-center mx-auto text-white">
        <ProfileCard username={USER_NAME} />
      </main>
      <footer className="fixed bottom-0 w-full text-center pb-4 text-white px-2">
        <p> © 2023. 문지웅 | All rights reserved.</p>
      </footer>
    </>
  );
}
import SocialIcons from "./SocialIcons";
import UserInfo from "./UserInfo";
import UserLinks from "./UserLinks";

const ProfileCard = ({ username }: { username: string }) => {
  return (
    <div className="w-full space-y-8 max-w-lg px-4 items-center flex flex-col">
      <UserInfo username={username} />
      <UserLinks username={username} />
      <SocialIcons username={username} />
    </div>
  );
};

export default ProfileCard;

3. 프로젝트 배포

- 프로젝트에 불필요한 파일들을 제거하여, 프로젝트를 정리합니다.

- ex) vercel.svg, next.svg 등

- 이번 프로젝트의 경우, github가 제공해주는 github-pages를 활용해서 {username}.github.io 로 배포할 예정입니다.

- 배포를 위해 github actions을 적용할 예정입니다.

4. github actions 적용하기

프로젝트가 github에 업로드되고 나면, settings로 이동합니다.

Pages를 클릭하면, GitHub Pages를 확인하실 수 있습니다.

Source가 기본적으로, Branch로 설정하도록 되어 있을텐데, 이를 GitHub Actions로 변경합니다.

변경하게 되면, GitHub가 next.js 프로젝트임을 알고 해당 Actions을 추천해줍니다.

configure 버튼을 클릭해서 들어가면 yaml 파일을 확인할 수 있습니다.

여기서 한 가지 수정이 필요합니다.

현재 node의 LTS 버전은 18버전이므로, 16을 18로 수정해줍니다.

또한, next.config.js 파일을 아래와 같이 수정합니다.

/** @type {import('next').NextConfig} */

const nextConfig = {
  output: "export",
};

module.exports = nextConfig;

GitHub Pages는 기본적으로 jekyll 기반이므로, root 디렉토리에 .nojekyll 파일을 추가해줍니다.

수정한 next.config.js 파일과 .nojekyll 파일을 commit하고 push하면 정상적으로 동작할 것입니다.

완성한 프로젝트는 아래 링크에서 확인하실 수 있습니다.

긴 글 읽어주셔서 감사합니다. 😊

8
0
심은광

심은광

[모두CBT] 문제집 출력 PDF 디자인을 업그레이드 했습니다 !

모두CBT는 온라인 문제풀이 서비스 뿐만 아니라 문제를 출력할 수 있는 서비스도 제공하고 있습니다.

모두CBT에 업로드 되어있는 자료들은 모두 출력이 가능하고, 유저가 직접 제작한 시험지도 출력이 가능합니다. !!

모두CBT가 어떤 서비스인지 궁금하시다면 아래 링크를 참고해주세요 !

모두CBT에서 기존에 제공하고 있던 PDF 디자인이 너무 단조롭다는 생각이 들어서 이번에 업그레이드를 하게 되었습니다.

BEFORE

스크린샷 2023-09-20 오전 2.15.53.png

AFTER

스크린샷 2023-09-20 오전 2.15.43.png

결과물이 꽤나 만족스럽네요 ㅎㅎ

만들고 보니, 다른 템플릿도 더 많이 만들어 보고 싶은 욕심이 생기는 것 같아요 !

다음에 더 멋진 템플릿 만들게 되면 다시 글 남기러 오겠습니다 :D

읽어주셔서 감사합니다.

모두CBT

국가고시 필답형 실기시험 준비를 도와주는 서비스입니다 .

9
0
정소영

정소영

09.19 개발 로그

디콰에 첫 로그를 올릴 때는 굉장히 낯설고 부끄러웠는데, 오히려 이렇게 올리고 나니 정리가 되서 좋다. 그리고 둘러보다가 좋은 글도 읽게 되어 굉장히 유익하다고 느낀다.

  • <역행자>에서 이런 얘기가 나온다. 경제적 자유를 얻고 싶다면 그 사람들이 모인 집단에 들어가면 된다. 꾸준히 나가다보면 저절로 물들게 된다고 나와있다. 디콰를 하면서 느끼는 게 그거였다. 개발자가 되려고 한다면 개발자들이 모인 집단에 들어가야 한다는 말이다.

  • 처음 디콰에 글을 올릴 때만 해도, 낯설고 부끄러웠다. 글 올리기가 부담스러워서 우물쭈물 하기만 했다면 나 혼자 TIL을 마무리 하지 못한 채 쌓여만 갔을 것이다. 하지만 그 낯섦을 깨고 오늘 내가 한 개발 공부를 올리게 되면서 스스로 뿌듯함과 정리된 생각을 얻게 됐다.

  • 덤으로 얻게 된 건, 현업 개발자들이 하는 고민, 공부, 관심기술 같은 것들을 둘러보게 되고 나 또한 그들의 정보를 얻어 시야(?)를 점점 넓힐 수 있게 되었달까. 여튼… 오늘은 디콰를 둘러보다가 ‘컴포넌트 분리’에 대한 좋은 블로그 글을 알아가서 굉장히 좋았다.



오늘의 로그는 아직 개발 진행형인 내용들이다.

  • homepage의 diaryItme을 grid와 list형식으로 보여주기

    list와 grid일 때의 디자인은 각각 구현하였으나 컴포넌트 렌더링 과정에서 문제가 발생했다. 기존 grid상태의 뷰를 보여주는 컴포넌트는 db데이터를 받아와 화면을 렌더링하는 서버 컴포넌트였다.

    이에 list라는 상태를 변화시켜 주기 위해 state를 사용하였으나, 이미 db데이터를 사용하고 있어 클라이언트 컴포넌트 변경이 안된다는 에러를 발생시키고 있다. =_=…. 고 한다…

  • 이곳저곳에 있는 modal을, hooks으로 만들기를 시도했다.

    이미 다 구현해놓고, 공통화를 한다는 건 참 힘든 일인 것 같다ㅋㅋㅋㅋ ’일단 공통인 부분을 찾아보자!’ 해놓고 코드부터 손을 댔는데, 한참을 헤멨다. 하나를 고치면 하나에서 에러가 나고, 공통인 부분을 찾았는데 모두 다 똑같이 생긴 모습은 아니어서 어디까지 공통 컴포넌트로 구현할 것인가에 대한 선택도 해야 했다.

교통 정리가 필요했다. 코드를 보면서 구현을 바로 하는 게 아니라. 각 모달이 어떤 기능과 형태를 가지고 있는지 정리를 먼저 해봤어야 했다

  • 어디까지 공통 컴포넌트로 만들 것인가?

  • 모달 디자인을 공통으로 만들 것인가? 나눌 것인가? ( 크게 두 디자인의 모달이 있다. )

modal.png

  • 모달의 공통기능
    - 버튼을 클릭하면 모달이 생긴다

    - 배경( 검정 반투명 ) 과 Box 형태가 같다.

    - 기능을 하는 버튼들이 있다.

    - 취소하기 버튼 → 모달이 꺼진다.

    - 배경을 클릭해도 → 모달이 꺼진다

  • 모달의 다른 기능
    - 모달 다자인이 크게 두 종류로 구분 ( 버튼리스트 / input+버튼 )

    - input + 버튼 디자인 모달

    ⇒ title / 버튼 공통 ( 함수 기능 )
    ⇒ 입력 부분은 차이

정리의 결과

hooks을 생성해 전체적인 공통 기능인 모달 on/off를 관리하는 state및 함수를 만들고, ModalForm 컴포넌트를 생성해서 배경과 Box는 모달 공통 style로 구현했다. 그리고 hooks을 만들어 모달 공통 기능 on/off와 그를 관리하는 state 및 함수를 구현했다.

ModalForm과 hooks에 있는 함수를 연결해 basic-Modal을 구현함. 빨간 네모는 모달 안의 children을 받아와서 ..어찌 해보면 될거 같다. 여러 가지 모달의 형태가 나올 수 있을 것 같지만 그건 내일의 나에게 맡긴다.

modal2.png


5
5
정소영

정소영

09.18 개발 로그

오늘은 유난히 집중이 안되는 날이었다. 코로나에 걸린 탓이라고 하자. 우리집에서 왜 나만 2번씩이나 걸리는지 모르겠다 ㅋㅋㅋㅋㅋ ( ㅠ_ㅠ ) 여튼 그래도 개발로그 업뎃한다.

  • deatilPage 디자인 개선 및 유저정보 추가

  • Comment 기능 추가

첫 페이지 ( Next.js의 라우터 대문ㅋㅋㅋ ) page.js는 어떤 기능을 하고 있는지 한눈에 알아보기 쉬운 편이 좋다고 생각한다. 그래서 detail의 page.js를 기능별 컴포넌트로 쪼개서 구현하였다. detailpage는 서버 컴포넌트이기 때문에 바로 DB와 연동하여 데이터를 받아왔고, 컴포넌트마다 필요한 데이터를 props로 넘겨주었다.

약간의 디자인 업그레이드와 함께 post정보와 user정보를 함께 보여주었다. detailpage에서 client컴포넌트가 되는 부분은 middleNavBar ⇒ 좋아요 / 글 수정 / 삭제버튼이 있는 컴포넌트와 댓글 컴포넌트다. 클라이언트 컴포넌트 있는 부분을 내일 더 고도화 작업( 공통화,hooks생성 등 ) 할 생각이다.

개발을 하면 할수록 느끼는 것은, 내가 생각 하는 것을 구체적으로 표현하게 된다는 점이다. ’뭔가 이렇게 하면 될 것 같은데?’ 라는 흐리멍텅한 생각이 ‘A랑 B랑 합쳐서 C를 만들어 볼 수 있을 거 같아’라는 방식으로 구체적인 방향으로 생각하게 되는 것 같다.

PLAN

오늘은 간단하게 댓글 기능을 구현했으니 내일은 집중해서 머리를 굴려봐야 할 거 같다

  • commentItme컴포넌트에서 API요청 hooks으로 만들기

  • DB연결 함수 hooks으로 만들어서 사용하기

  • modal공통으로 사용하는 부분 찾아서 hooks으로 만들기 mypage-profile 수정 / detailpaeg-comment입력 / detailpage - 햄버거Icon ( 옵션버튼 )

5
0
정소영

정소영

9월 17일 개발로그

구현내용

이미지 미리보기 기능이 필요한 곳이 3 곳이 있다.

postpage / editpage / mypage의 유저프로필 수정 부분이다. 이 세 페이지에서 다 같은 코드를 사용하므로 이미지 미리보기 util함수를 생성하여 공용으로 사용하도록 했다.

postpage의 input / image / button 부분을 나눠 각각 컴포넌트화 시킨 후, editpage에서도 공용으로 사용할 수 있도록 하였다. 하나의 페이지를 컴포넌트로 나누면서 전역으로 데이터를 공유할 필요가 생겼다. 그래서 contextAPI를 사용해 image와 postdata를 contextAPI로 만들어 전역으로 사용하였다.

  • 글 작성 / 수정 기능 서버 api 요청 hooks으로 구현 → 공용 사용

  • 사용자 입력 받는 input도 hooks으로 구현

post와 edit페이지에 있는 버튼 컴포넌트는 공통화를 고민중이다. 지금은 하지 않는게 더 나을거라는 판단을 해서 하지 않았지만, 개발 하다보면 더 좋은 아이디어가 떠오르면 언젠가 합칠수도. 코드가 바뀔 수도 있을 것 같다.

마무리

hooks을 만들고 컴포넌트를 공통화 하면서 느끼는 부분이 있다. 이전에는 하나의 함수는 하나의 기능을 한다고 생각했다. handleClickPostAdd라면 post를 작성하는 함수라고만 생각했을 텐데ㅋㅋㅋ 하지만 그 안에서도 다양한 기능들이 있음을 인지했다.

그 기능이 중복된다면 따로 빼서 어떻게 구현해 볼 수 있을까, 이 함수를 utils로 만들었을 때 어떤 데이터를 필요로 하는지 고민하고 있는 내 모습을 발견했다.!!!! 프로젝트에서 코드를 나누고 쪼개고 붙이는 연습을 해보면서 컴포넌트와 함수가 하나의 구체적인 일(?), 역할(?)을 하도록 만들고 싶어졌다.

코드는 엄청 많이 바뀌었는데 왜ㅋㅋㅋ겉 표지는 별로 바뀐 게 없지… 티가 나지 않는다!@_@ 케헥. 그래도 어제 쓴 대로 오늘 구현했다. 나름… 선언했다고 개발하고 로그까지 올린다. 오늘이 마무리 끝, 좋다.

내일은.

댓글기능 ㄱㄱ ㅋㅋ

5
0
심은광

심은광

[모두CBT] 제휴업체와 첫 콜라보 상품을 출시했어요 !!

안녕하세요 저는 국가고시실기 시험준비생들을 위한 서비스 모두CBT를 개발 및 운영하고 있어요 !!

모두CBT가 궁금하시다면 아래 글을 봐주시면 좋을 것 같아요.

이번에 문제집을 출판하는 업체와 제휴를 맺게 되면서, 콜라보로 첫 상품을 출시 했습니다 !!

저자님께서 주신 원고를 모두CBT에 올려서 온라인으로 학습이 가능하도록 구성했어요 ㅎㅎ

어제 출시했는데 !! 벌써 반응이 꽤나 좋네요 :D

유저 플로우나, 할인쿠폰 시스템 등등 서비스적인 부분은 전적으로 저한테 맡겨주셔서 열심히 고민해서 구성하고 개발했습니다 ㅎㅎ

어려운 기능은 없었는데, 할인쿠폰 시스템등은 새로 도입하다보니 생각보다 시간이 좀 걸렸던 것 같아요.. !

뭐 어쩃든, 모두CBT에 프리미엄 플랜이 하나 추가돼서 너무 행복합니다 !!

스크린샷 2023-09-12 오후 6.10.52.png

저의 자랑글 읽어주셔서 감사합니다 :D

모두CBT

국가고시 필답형 실기시험 준비를 도와주는 서비스입니다 .

7
2
민서

민서

생성/파괴 vs Object Pooling

들어가며

Instantiate와 Destroy는 Unity에서 제공하는 오브젝트 생성, 파괴를 담당하는 코드입니다. Object Pooling은 이러한 생성과 파괴 비용이 비싸기 때문에 대안으로 나온 최적화 기법입니다. Object Pooling의 경우는 자료구조 Queue만 알고 있어도 원리를 알고 사용할 수 있다는 장점 덕에 Unity를 입문하시는 분들이 가장 먼저 배우는 최적화 기법이기도 합니다. 그래서 저는 저번 주에 이 두 가지 방식을 직접 구현해보고 비교해봤습니다. 근데 생각치도 못한 난관에 생각보다 오래 걸려서 어제 작성해야 했는데 오늘까지 분석해보고 이제서야 결과를 내게 되네요. 지금까지의 생각보다 험난했던 과정을 여러분들께 소개해드리도록 하겠습니다.

Object Pooling이 나오게 된 배경

C#의 주목할만한 특징 몇 가지 중에 재밌는 특징이 있습니다. C#은 Garbage Collector라는 친구가 있어서 아무도 안쓰는 메모리가 있다면 알아서 수거해가는 친구인데요, 이 덕분에 C++ 처럼 메모리 관리를 안해줘도 괜찮다는 장점이 있습니다. 하지만 단점은 개발자가 메모리 관리를 할 수 없어요(?). Garbage Collector가 작동하는 방식은 프로그램을 멈추고 메모리를 회수한 뒤에 다시 프로그램을 재개하기 때문에 멈추고 재개하는 그 과정에서 프레임 드랍이 일어납니다. 소위 랙이라고 불리는 현상이 나타나죠. 그렇기 때문에 개발자들은 가비지가 안나오게끔 코드를 짜는 방식으로 발전해옵니다. 메모리 관리를 하지 않게 하기 위해 Garbage Collector를 만들었는데 정작 개발자들은 Garbage Collector가 사용되지 않게끔 코드를 짜는 아이러니한 일이 일어나고 있습니다. 그 중 하나가 Object Pooling입니다. Object Pooling은 간단합니다. 오브젝트를 제거할 때 이러한 가비지가 나오는 것이 거의 확정이기 때문에 미리 만들어두고 Queue에 넣어둔 뒤 필요할 때 꺼냈다가 삭제하는 것이 아닌 다시 Queue로 넣어 재사용한다는 목적으로 만든 최적화 기법이예요.

직접 구현해서 비교해보자

image.pngimage.png

생각보다 gif 파일 용량이 커서 사진으로 대체하겠습니다

생성/파괴의 경우 최저 프레임이 28프레임이 나왔고

Object Pooling의 경우 최저 프레임이 35프레임이 나왔습니다.

Garbage Collector(황토색?)와 Script(파란색)의 그래프만 뜨도록 표시를 했는데 분명 차이가 있어야 하는데 차이가 없어서 당황했습니다.

image.png

차이가 있긴 하지만 이대로 끝내긴 너무 찝찝했습니다. 생각했던 것보다 Instantiate/Destroy에서의 Garbage Collector가 활발하지 않았고 성능 차이도 10프레임 정도의 차이 밖에 안났던 것입니다.

그래서 선배께 도움을 청해 제 코드가 잘못된 것인지 확인해주실 수 있는지 요청을 드렸고 결과는 비슷했습니다.

image.png

솔직히 아무 의심도 없이 당연히 무조건 써야한다, 좋다고만 생각했던 Object Pooling과의 성능 차이가 얼마 나지 않아 뒤통수를 쌔게 맞은 느낌이 들었습니다.

그래서 결국 의미는 없었는가

선배와 제가 그때 당시 내린 결론은 Unity 2022 에서 제공하는 Instantiate와 Destroy의 코드는 최적화를 잘해서인지 그렇게 비용이 비싸지 않았던 것 같다. 그래서 Unity 2017 버전에서 돌리면 유의미한 차이가 있을 것이다 였습니다. 그리고나서 계속해서 테스트를 해본 결과

image.png

드디어 납득이 갈만한 결과가 나왔습니다. 저희가 테스트했던 환경에서는 생성했던 객체(총알)이 그저 앞으로 나가는 기능밖에 없었기 때문에 별 차이가 없었으나 실제 게임은 다릅니다. 이것보다 오브젝트 하나하나가 훨씬 무겁겠죠.

결론은 생성되는 오브젝트가 무거우면 무거울수록 Object Pooling에 의미를 갖게 되는 것 이였습니다.

오브젝트가 생성할 때 실행되는 초기화 코드(Start() 함수, Awake() 함수)가 계속 실행되느냐 vs 한번 실행되느냐 의 차이는 컸기 때문입니다.

마무리하며

사실 원래 여기에 DOTS(Data Oriented Technology Stack) 방식으로 구현한 탄막 게임까지 같이 비교하여 포트폴리오를 작성하려고 했으나 생각지도 못했던 부분에서 오래걸리기도 하였고, DOTS 방식의 코딩 스타일이 기존의 객체 지향 프로그래밍 방식과 전혀 달라 일주일 내로는 무리였습니다. 하지만 당연하게 사용해왔던 이러한 최적화 기법을 직접 비교해보고 관찰함의 과정을 통해 더 유의미한 시간을 보낼 수 있었던 것 같습니다. 이 에피소드는 앞으로도 기억에 남을 것 같네요 재밌었습니다. 다음주에는 혹은 다다음주에는 DOTS를 구현하고 찾아뵙도록 하겠습니다.

4
2
심은광

심은광

카카오톡 오픈채팅 봇 대여 시스템 구축 완료, 서비스시작 !

저는 오픈채팅방을 운영하고 있는데 오픈 채팅방 활성화를 위해 봇을 개발해서 활용하고 있습니다.

카카오톡 오픈채팅 봇은 디스코드 봇, 슬랙 봇 처럼 확장성이 좋거나 기능을 고도화하는 데에는 한계가 있지만,

타 채팅 봇에 비해 월등한 접근성을 갖추고 있어서 경쟁력이 있는 것 같아요 !

적어도 한국에서는 카카오톡을 안하는 사람을 찾기가 더 어려울 정도니까요 ㅎㅎ

제가 개발한 오픈채팅봇이 궁금하시다면 아래 게시글을 봐주세요 !!

최근에는, 유저분들이 오픈채팅 봇을 단톡방이 아닌 개인톡에서도 활용하고 싶다는 의견을 주셔서 개발에 돌입했습니다 !

@사용자 인증에 대한 고민 ..

오픈채팅 봇 대여를 위해서 사용자 인증에 대한 고민이 필요했습니다..

제가 개발한 시스템에서 카카오톡을 통해 받아 올 수 있는 고유 정보는 닉네임 정도가 전부였습니다..

그래서 닉네임을 활용해야 겠다고 생각했고, 결과적으로 완성된 인증절차는 다음과 같습니다!

1. 시크릿 코드를 생성해서 유저에게 전달

2. 유저는 닉네임을 시크릿 코드로 변경

3. 봇이 유저의 닉네임을 인증코드로 활용해서 데이터를 전달

현재까지는 위 같은 형태로 인증방식을 구현했고, 약 일주일간 운영해 본 결과 다행히 큰 문제 없이 잘 운영되고 있는 것 같습니다 ㅎㅎ

오픈채팅봇을 대여해서 이용중인 회원님들

스크린샷 2023-09-11 오전 10.15.56.png

처음에 유저분들이 개발해달라고 해서 시작했는데..

아무래도 유료로 운영하다 보니 수요가 엄청 많지는 않았어요 ㅠㅠ..

현재는 약 여섯 분 정도가 신청해주셨네요 ㅎㅎ

그래도 분명 수요는 있었고 가능성은 본 것 같습니다 !

시간이 나면 좀 더 고도화를 진행해 볼 생각이에요.

읽어주셔서 감사합니다 !!

모두CBT

국가고시 필답형 실기시험 준비를 도와주는 서비스입니다 .

8
2
문지웅

문지웅

QR 코드 생성기 만들기: Next.js와 TypeScript로 시작하기

개요

이 글에서는 QR 코드 생성기를 만드는 단계별 가이드를 제공합니다.

Next.js와 TypeScript를 사용하여 QR 코드를 입력하고 생성하며,

생성된 QR 코드를 다운로드할 수 있는 웹 애플리케이션을 개발하는 방법입니다.

목차

  1. 소개

    • QR 코드란?

    • 프로젝트 개요

  2. 프로젝트 설정

    • 프로젝트 초기 설정

  3. UI 구성

    • 전체 레이아웃 구성

    • 입력 필드 추가

    • QR 코드 생성 버튼 추가

    • QR 코드 표시 영역 추가

  4. QR 코드 생성

    • react-qr-code 라이브러리 설치

    • QR 코드 생성 로직 구현

  5. QR 코드 저장

    • file-saver 라이브러리 설치

    • QR 코드 저장 기능 추가

  1. QR 코드에 효과 추가

    • framer-motion 라이브러리 설치

    • QR 코드 div 수정

  1. 프로젝트 테스트

    • QR 코드 생성 및 저장 테스트

  2. 결론

    • 구현 결과 및 평가

소개

QR 코드는 Quick Response Code의 약자로, 빠르고 쉽게 정보를 전달하는 데 사용되는 2차원 바코드입니다. 이번 프로젝트에서는 Next.js와 TypeScript를 사용하여 QR 코드 생성기를 만들어보려고 합니다. 사용자가 입력한 데이터를 기반으로 QR 코드를 생성하고, 생성된 코드를 이미지로 저장할 수 있는 웹 애플리케이션을 구현할 것입니다.

프로젝트 설정

Next.js 공식문서의 프로젝트 생성 가이드대로, 아래 명령어로 프로젝트를 생성합니다.

npx create-next-app@latest

UI 구성

프로젝트의 UI를 구성하기 위해, 먼저, 제목 부분과, QR 생성기 부분으로 나눕니다.

QR 생성기에 입력 필드, QR 코드 생성 버튼, 그리고 QR 코드 표시 영역을 추가합니다.

// app/page.tsx

import QRGenerator from "@/components/QRGenerator";
import Title from "@/components/Title";

export default function Home() {
  return (
    <main>
      <Title />
      <QRGenerator />
    </main>
  );
}

입력 필드 생성

QR 코드에 들어갈 내용을 입력하기 위한 입력 필드를 구현합니다.

interface QRCodeInputProps {
  value: string;
  onChange: (value: string) => void;
}

const QRCodeInput = ({ value, onChange }: QRCodeInputProps) => {
  return (
    <input
      type="text"
      value={value}
      className="border w-full md:w-3/4 mx-auto px-4 rounded-lg text-lg mt-4"
      placeholder="Enter Text"
      onChange={(e) => onChange(e.target.value)}
      autoFocus
    />
  );
};

export default QRCodeInput;

QR 코드 생성

QR 코드 생성을 위해 react-qr-code 라이브러리를 사용하겠습니다.

이 라이브러리를 설치하고 QR 코드 생성 로직을 구현합니다.

npm install react-qr-code
"use client"; // useState 사용을 위해, client component 사용

import { useState } from "react";
import saveAs from "file-saver";
import QRCode from "react-qr-code";
import { motion } from "framer-motion";
import QRCodeInput from "./QRCodeInput";
import Button from "./Button";

const QRGenerator = () => {
  const [qrData, setQrData] = useState<string>("");
  const [isGenerated, setIsGenerated] = useState<boolean>(false);

  const handleInputChange = (value: string) => {
    setQrData(value);
    setIsGenerated(false);
  };

  const generateQRCode = () => {
    if (qrData) {
      setIsGenerated(true);
    }
  };

  return (
    <>
      <QRCodeInput value={qrData} onChange={handleInputChange} />
      <Button
        onClick={generateQRCode}
        disabled={qrData === ""}
        title="Generate QR Code"
      />
      {isGenerated && (
        <>
          <div className="border p-2">
            <QRCode value={qrData} />
          </div>
        </>
      )}
    </>
  );
};

export default QRGenerator;

QR 코드 저장

생성된 QR 코드를 이미지로 저장하기 위해 file-saver 라이브러리를 사용합니다. 이 라이브러리를 설치하고 QR 코드 저장 기능을 추가합니다. TypeScript 프로젝트이므로, @types/file-saver 도 필요합니다.

npm install file-saver @types/file-saver 
import saveAs from "file-saver";  
// ...
const saveQRCode = () => {
    if (isGenerated) {
      const svgString = document.querySelector("svg")?.outerHTML;
      
      if (!svgString) return;

      const blob = new Blob([svgString], { type: "image/svg+xml" });
      saveAs(blob, "qrcode.svg");
    }
  };

// ...

※ 기능 추가

framer-motion을 추가하여, QR Code가 생성될 때, animation을 추가했습니다.

// ...          
<motion.div
      className="border p-2"
      initial={{ opacity: 0, scale: 0.5 }}
      animate={{ opacity: 1, scale: 1 }}
      transition={{ duration: 0.5 }}
      >
       <QRCode value={qrData} />
</motion.div>
// ...

완성된 QRGenerator 코드

"use client";

import { useState } from "react";
import saveAs from "file-saver";
import QRCode from "react-qr-code";
import { motion } from "framer-motion";
import QRCodeInput from "./QRCodeInput";
import Button from "./Button";

const QRGenerator = () => {
  const [qrData, setQrData] = useState<string>("");
  const [isGenerated, setIsGenerated] = useState<boolean>(false);

  const handleInputChange = (value: string) => {
    setQrData(value);
    setIsGenerated(false);
  };

  const generateQRCode = () => {
    if (qrData) {
      setIsGenerated(true);
    }
  };

  const saveQRCode = () => {
    if (isGenerated) {
      const svgString = document.querySelector("svg")?.outerHTML;
      
      if (!svgString) return;

      const blob = new Blob([svgString], { type: "image/svg+xml" });
      saveAs(blob, "qrcode.svg");
    }
  };

  return (
    <>
      <QRCodeInput value={qrData} onChange={handleInputChange} />
      <Button
        onClick={generateQRCode}
        disabled={qrData === ""}
        title="Generate QR Code"
      />
      {isGenerated && (
        <>
          <motion.div
            className="border p-2"
            initial={{ opacity: 0, scale: 0.5 }}
            animate={{ opacity: 1, scale: 1 }}
            transition={{ duration: 0.5 }}
          >
            <QRCode value={qrData} />
          </motion.div>
          <Button
            onClick={saveQRCode}
            disabled={!isGenerated}
            title="Save QR Code"
          />
        </>
      )}
    </>
  );
};

export default QRGenerator;

프로젝트 테스트

전체 소스 코드를 다운 받고 npm run dev 로 실행할 수도 있고,

아래 링크에서 직접 테스트도 가능합니다.

웹 애플리케이션을 실행하고 실제로 QR 코드를 생성하고 저장해보시기 바랍니다.

결론

이미 만들어진 QR Code 라이브러리를 활용해서, 쉽고 빠르게 QR Code 생성기를 만들어 볼 수 있었습니다.


※ 참고 1) 전체 소스 코드

※ 참고 2) 프로젝트 이름 배경

QRQuasar: QRQuasar는 강력한 QR 코드 생성 도구로, 빠른 속도와 높은 효율성을 특징으로 합니다. (ChatGPT)

긴 글 읽어주셔서 감사합니다. 👍

10
0
정소영

정소영

Next.js를 사용해 일상공유 Diary 서비스 만들기

Next.js를 사용해 Diary프로젝트를 진행하고 있다. 팀프로젝트를 하기 어려운 상황도 있었고, Next.js를 통해서 백엔드까지 구현할 수 있다는 것, 그리고 SSR( 아직까지 크게 와닿지는 않지만.. )을 공부할 수 있다는 생각에 더 큰 흥미를 느껴서 도전해보게 되었다. 강의를 들으면서 작은 토이프로젝트를 구현해보고, 그것을 바탕으로 Next.js기반의 프로젝트를 구상했다.

Next.js는 React.js와 비슷하지만 가장 뚜렷하게 큰 특징은( 내가 생각하기에 ㅋㅋ) (1)라우터와 (2) 서버 / 클라이언트 컴포넌트가 나뉘어져 있다는 것이다. 프로젝트를 만들면서 이 부분에 조금 고민이 많았던 것 같다.

(1) 라우터 : 폴더 경로에 따른 파일 시스템 계층 구조로 이루어져 있다. 폴더를 생성하면 그에 해당하는 페이지가 연결되는 방식이다. 프로젝트가 진행되면서 페이지가 하나씩 추가되었고, 해당 폴더도 늘어갔다. 폴더 관리를 어떻게 하는 것이 좋을까 하는 고민도 자연스럽게 하게 되었고, 이번 프로젝트에서는 페이지별로 컴포넌트와 스타일 파일을 관리해보는 것으로 선택했다.

(2) 서버 컴포넌트와 클라이언트 컴포넌트가 구분되어 있어서, 각각의 특징에 맞게 코드를 작성해야 했다. React.js에서 사용했던 useEffect, useState와 같은 hooks들은 서버 컴포넌트에서 사용할 수 없었다. 그래서 그들을 사용하려면 use client를 사용해야 했다.

Next.js는 SSR을 구현하기 위한 프레임워크다. 서버에서 렌더링 한 페이지를 클라이언트에 보내줘 빠른 로딩이 되게 하는 게 장점이다. 그렇기 때문에 서버 컴포넌트를 최대한으로 사용하고 사용자와 인터렉션이 있어야 하는 부분( 버튼 같은? )을 클라이언트 컴포넌트로 구현하는 것이 핵심이다. 왠지 'use client'를 쓰면 지는것 같은 느낌이ㅋㅋㅋㅋ 누가 답을 알려주면 참 좋겠다는 생각을 굉장히 많이 했다.

GPT에게 '내가 이렇게 생각해서 이렇게 구현했는데 이게 맞아? '라는 형태로 질문을 하면서 내가 이해한 내용을 확인하고, 잘못 이해한 부분은 다시 찾아보며 공부하는 형태로 프로젝트를 진행해갔다. 물론 GPT는 21년도 까지의 내용이 있기 때문에 대부분의 Next.js내용은 공식문서를 비교하며 봐야했다ㅋㅋㅋ 그 외에도 개발 전반적인 내용 비동기처리, react, js등의 여러 내용을 추가적으로 공부할 수 있는 기회가 됐다.♡

오늘까지 완성된 프로젝트의 진도는@_@ version01로,

  • 기본 페이지 ( 홈 / 로그인 / 회원가입 / 작성 페이지 / 마이페이지 / 수정페이지 )는 완료.

  • 기능은 회원가입 / 로그인 / 글작성 까지는 된다!!

아직은 개발중인 프로젝트의 개발 진행기다. 다음주에는 마이페이지 기능구현과 로그인 여부에 따른 세부적인 부분을 봐야할 것 같다. 뭔가 혼자 끄적거리는 것처럼 글을 썼더니 반말체가 되어버렸네요. 마무리만 존대로ㅋㅋㅋ 더 딥한 이야기는 블로그와 노션에 있어요. 모든 이야기를 공유하고 싶지만 시간이 늦었으므로. 이만 여기까지 하겠슴니다.

★blog

8
2
심은광

심은광

모두CBT 서비스가 처음으로 제휴를 맺게 되었습니다 !!

“모두CBT” 서비스를 시작한 지 7개월 만에 드디어 첫 제휴를 맺게 되었습니다 !!

제가 운영하는 서비스가 관련 분야에서 어느 정도 입소문이 났는지,

문제집 관련 출판을 하는 업체에서 먼저 연락을 주셨습니다.

몇 차례 얘기를 나눈 끝에 서로에게 도움이 될 만한 협업 방안을 찾게 돼서 제휴를 맺게 되었습니다 ㅎㅎ

작은 개인 프로젝트로 시작해서, 업체와 협업을 하게 되는 날이 올 거라곤 상상도 못했는데 너무 신기하고 즐거운 경험인 것 같습니다!

협업 관련해서 개발이 완료되면 또 메이커로그 남기러 오겠습니다 :D

@모두CBT x EHSmaster

스크린샷 2023-09-07 오후 12.39.31.png

모두CBT

국가고시 필답형 실기시험 준비를 도와주는 서비스입니다 .

8
4
김성연

김성연

라즈베리파이와 함께한 개발 커리어

안녕하세요, 고1 학생 주니어 개발자 김성연입니다!

제가 익주에 중간고사 이슈가 있기 때문에 금주의 메이커로그는 과거의 이야기로 대체합니다.

이번 메이커로그에서 저는 라즈베리파이로 시작된 제 개발 커리어의 시작과 현재까지의 과정을 쭉 회고하려고 합니다.

때는 2년 전인 2021년, 제가 중학생 2학년 시절로 돌아갑니다.

저는 여느 중학생과 같이 학업에 크게 관심도 없고 그렇다고 별다른 취미도 없는, 흘러가는 대로 시간을 낭비하며 사는 평범한 중학생 중 하나였습니다.

그러던 중에 경기도에서 학생주도형 교육 활동인 "꿈의 학교" 라는 프로그램을 우연히 알게 되었고, 파이썬으로 인공지능 앱을 만드는 활동에 흥미가 생겨 신청을 해보았습니다.

Screenshot 2023-09-06 at 0.46.34.png

결론적으로 해당 수업에선 코로나 이슈로 인해 대면 수업도 한 번으로 제한됐었고 멤버들 간의 시간 조율에 실패해서 목표하는 앱은 만들지 못했지만, 해당 수업의 운영진과 개인적으로 친해질 수 있었습니다.

운영진과의 친밀감 향상 외에도 저에게 큰 도움이 되었던 것이 있는데, 바로 학급비였습니다.

당시 경기도에서 꿈의 학교 사업을 많이 밀고 있던 터라 학급비가 상당히 빵빵했는데, 저희는 그 학급비로 학급 인원 10명 모두에게 12만원 정도의 라즈베리파이를 모두 지급했고, 이외에도 2만원 상당의 샤프와 노트, USB 등 다양한 물품을 제공받았습니다.

세금도 안 내면서 이렇게 많이 받아도 되나 싶을 정도로 받았습니다

다른 건 그리 중요한 게 아니라 제쳐두고, 저에게는 이 라즈베이파이라는 물건이 신기했습니다.

작주의 메이커로그에 상기하였듯이, 당시 저는 파이썬으로 디스코드 봇을 만드는 데에 관심이 많았고 당시 서버가 없어 제 개인 컴퓨터가 켜져 있는 낮 시간 동안에만 제 개인 디스코드 봇을 서비스할 수 있었는데, 라즈베리파이를 쓰면 저전력 CPU라서 24시간 돌릴 수 있다는 사실을 알고 흥미가 생겼습니다.

그래서 친해진 운영진과 열심히 삽질을 해보며 디스코드 봇을 호스팅하는 데에 성공했고, 이후 1년이 지난 2022년에는 이 라즈베리파이로 무엇을 해 볼 수 있을지 고민이 되었습니다.

그리고 웹을 배워서 호스팅을 해 보자는 목표를 세우게 되었고, 생활코딩 님의 무료 유튜브 강의를 보며 기초적인 웹 지식을 쌓고 열심히 삽질을 해 본 결과 kro.kr의 무료 도메인으로 라즈베리파이로 24시간동안 웹 호스팅을 하는 데에 성공하게 됩니다.

그리고 제 라즈베리파이가 죽습니다.

모종의 이유로 라즈베리파이의 전원 공급에 문제가 생겼고, 그대로 12만원 상당의 라즈베리파이가 죽었습니다.

이걸 처리할 길도 없어 부품이 필요하다던 지인에게 무료로 처분했고, 저는 친해진 운영진에 중고로 반값인 5만원에 라즈베리파이를 구매해서 다시 열심히 삽질해서 복구를 하게 됩니다.

그렇게 잘 쓰나 하던 어느 날, 라즈베리파이가 또 죽습니다.

제가 라즈베리파이를 하드디스크 바로 위에 올려두고 써둔 탓에 간섭이 일어나 1TB 하드디스크와 라즈베리파이, 물려놓은 USB까지 모두 죽었습니다.

하드디스크에 들어있던 영화 파일과 라즈베리파이에 들어 있던 개발 파일이 모두 사라져서 당시 상실감이 심했던 기억이 있네요.

이후 그 사건을 계기로 파일 백업의 중요성과 서버 세팅 장소의 중요성을 크게 깨닫게 되었고, 당근마켓에서 성능이 낮은 라즈베리파이를 또 중고로 구매하게 됩니다.

마침 제가 변화를 갈망하던 시기였기에 저는 무료 도메인인 kro.kr이 아닌, 유료 도메인을 사용해서 url을 예쁘게 만들고 싶었습니다.

그래서 홀린 듯이 hosting.kr에 들어가 1년에 만 원짜리인 kinn.kr이라는 예쁜 도메인을 얻게 되었고, 열심히 삽질을 한 끝에 cloudflare을 통해서 제 라즈베리파이와 연동하는 데에 성공했습니다.

Screenshot 2023-09-06 at 1.07.01.png

이후 저는 웹을 계속 배워나가면서 제 웹사이트에 실시간으로 적용하며 실력을 키워나갔고, 1년이 지난 2023년의 지금도 현재 진행형입니다.

이것이 중학교 2학년에서 고등학교 1학년이 되면서 제가 이루어 낸 발전입니다.

누군가에겐 정말 아무것도 아닌 것처럼 느껴질 수는 있지만, 학업에도 개발에도 재능이 없는 제가 열심히 삽질해보며 제가 원하는 결과를 이뤄내는 경험은 저에게는 정말 값진 경험이었고, 이 쾌감을 계속 느끼며 개발 생활을 이어나가기 위한 첫 걸음을 나름 잘 뗐다고 생각합니다.

아무 생각 없이 흘러가던 대로 살던 제가 성공주의자가 되어 열심히 사는 삶을 갈망하는 사람으로 바뀌게 된 계기 중 하나가 경기도 꿈의학교에서 만난 운영진들과 같이 개발에 관한 지식을 쌓아가며 흥미를 느껴간 것도 있는 것 같네요.

여담을 더 끄적여보자면, 저는 당시 만난 두 명의 운영진들과 대한민국 애플 스토어 3~5호점을 모두 오픈런을 할 정도로 개인적으로 정말 많이 친해져서 이 수업을 신청한 과거의 저에게 너무 고마운 감정을 느낍니다.

이제는 경기꿈의학교가 경기이룸학교로 바뀌며 학생주도학습이 사라지고 교사주도학습으로 바뀐 것을 보고 많이 아쉽긴 하지만 중2의 저에게는 굉장히 좋은 기억으로 남아있었습니다.

제가 당시 경기도 도지사가 누군지도 모르고 이런 사업을 주최한 기관이 어디인지도 모르겠지만 제가 이런 좋은 인연을 찾을 수 있게 도와준 경기꿈의학교 측에도 감사하다는 말씀을 드리고 싶습니다.

또 제가 작년에 구매한 kinn.kr 도메인으로 추가로 할 수 있는 것을 찾아보다가 cloudflare에 이메일 라우팅이 있어서 kinn@kinn.kr 이라는 예쁜 이메일 주소도 얻게 되었네요 ㅋㅋㅋ

저는 지금 https://kinn.kr/ 이라는 개인 웹사이트에서 실시간으로 제 개발 역량을 쌓아가고 있고, 앞으로 React, Swift 등을 배우며 계속 성장해 나가고 싶습니다.

아직 정말 많이 부족한 실력임에도 꾸준히 성장해서 디스콰이엇에 글 쓰시는 분들처럼 제 역량이 많이 강화되길 바라며 회고록 마치겠습니다.

두서 없는 긴 글 읽어주셔서 진심으로 감사드립니다.

8
6
민서

민서

효율적인 UI 구조를 위해 MVP 패턴을 사용해보았습니다

들어가며

안녕하세요 저는 특성화고 컴퓨터게임제작과를 다니며 현재는 특기자 전형을 위한 포트폴리오를 준비 중인 고3 민서라고 합니다. 저는 현재 포트폴리오에 저의 가치를 드러낼 수 있는 내용을 적기 위해 고민하고 개발해나가고 있는데요. 포트폴리오를 채워나가면서 구조 설계, 디자인 패턴과 관련된 얘기가 들어가면 좋겠다고 생각하여 오늘 소개할 주제를 선정하게 되었습니다.

MVP 패턴은 무엇일까

MVP 패턴은 Model, View, Presenter 세 가지 요소로 UI를 관리하는 디자인 패턴입니다. Model은 데이터를 가지고 있고, View는 사용자에게 보여지는 UI를 Presenter는 Model의 데이터와 View의 UI 기능을 관리하는 친구입니다. 제가 공부했던 블로그의 사진은 이렇게 소개하고 있네요

image.png

UI는 너무 활용도가 넓고 한 객체마다 어디까지 책임을 부여하고 분리해야 할지 판단하기 어려웠고 UI 구성을 조금이라도 바꾸면 이곳저곳에서 나오는 오류들 때문에 항상 게임 개발할 때마다 UI 작업을 제일 싫어했던 기억이 나네요. 그렇기에 지금이라도 공부해야 한다고 생각했습니다.

뭔가 구현했던 구조들을 다 설명하려고 했는데 그렇기에는 글이 너무 길어지고 TMI일 것 같아서 싹 다 지우고 어떤 형태로 구현했는지만 간단하게 그려보겠습니다.

image.png

이건 실제로 제가 테스트해보기 위해서 만들었던 팝업창 UI입니다. Bind 함수를 통해 팝업창에서 어떤 텍스트가 띄워질 것인지, 버튼에 표시되는 텍스트는 무엇인지, 버튼이 어떤 기능을 수행하는지를 넘겨주면 Presenter에서 정보를 받아 View로 표시해주는 거죠. Unity와 C#의 특징 덕분에 구현하다 보니 앞에 보여줬던 사진의 구조와는 다르게 View는 Presenter를 몰라도 되고 Presenter는 Model을 몰라도 되게 되었습니다. 결합도가 느슨해졌다는 것이니 오히려 좋아요

더 개선할 수 있지 않을까?

제가 짠 코드에서 View 기능을 담당하는 코드는 ViewBase라는 객체에서 모든 역할을 다 해주기 때문에 사실 View 코드는 매우 간단합니다.

image.png

View에서는 사실 보여지는 부분만 관리하기 때문에 각 View마다의 차이점은 UI가 어떻게 구성되어있는지 밖에 없습니다. 그렇기 때문에 저는 ViewBase 라는 부모 클래스를 만들어주고 UI의 공통적인 특성(ESC를 통해 닫을 수 있다, 중첩이 가능하다, 게임이 시작하자마자 보인다 등등)을 정의해놨기 때문에 View의 코드는 매우 간단해질 수 있었던 것이죠. 하지만 어차피 다른 프로젝트에서도 계속 재활용하며 사용할 코드라면 더 편리했으면 좋겠습니다.

CodeDOM을 사용해보자

CodeDOM은 C#에서 제공하는 기능 중 하나로 무려 런타임 중에 코드를 생성할 수 있게 해줍니다. 물론 그만큼 느리기 때문에 보통 인게임에서는 사용하지 않고 제 경우와 같은 에디터를 만들거나 개발 툴을 만들 때 사용합니다.

CodeDOM을 사용해서 우선 UI를 배치하고 그 UI를 인식하여 코드를 짜주는 친구를 만들면 좋지 않을까라는 아이디어로 시작해서 결국

녹화_2023_09_03_23_00_50_112.gif

성공했습니다! 처음 다뤄보는 기능이기도 하고 자료가 공식 문서밖에 없어서 중간에 오류가 많았지만 잘 작동하는 것을 보니 기분이 좋네요

마무리하며

제가 여러 현업 개발자들을 만나며 얻었던 조언 중 하나는 게임 개발자들을 각자 자신만의 ‘자산’을 보유하고 있다는 것이었습니다. 자산이 잘 쌓여있는 개발자는 코드 조금만 짜도 하나의 게임을 금방 완성할 수 있을 정도라고 하더라구요. 처음 맨땅에서 게임을 만드는 것은 무척이나 어려운 일이기 때문에 이번 주에 만든 MVP 패턴과 같이 미리 구조와 기능을 만들어두면 이 코드는 모든 프로젝트에서 쓸 수 있게 되고 그것이 저의 자산이 된다는 이야기였습니다. 이번 주는 그런 오래 두고두고 쓸 ‘자산’을 만들었다는 점에서 매우 의미가 깊었던 그리고 배울 것이 많았던 주였던 것 같습니다.

다음 주에 만들 것

다음 주는 포트폴리오에 최적화에 관한 이야기가 들어가면 좋을 것 같아서 이번에 새로 Unity에서 선보인 DOTS(Data Oriented Technical Stack) 와 기존 C#의 Garbage Collector의 단점을 보완하기 위해 만든 Object Pooling, 이 두 가지 최적화 기법을 비교하는 보고서를 작성해보려고 합니다. DOTS는 멀티스레드와 연관이 있는 내용이라 얼마나 어려울지, 오래 걸릴지는 감도 안 잡히지만 그래서 그런지 기대가 되기도 합니다.

사실 이런 글을 써보는 게 거의 처음이라, 다른 분들의 글을 보면서 어디까지 간결하게 쓰고, 어디까지 자세하게 써야 할지 모르겠어서 고민하며 지우고 쓰고를 반복하다 보니 꽤 오래 걸렸습니다. 최대한 간결하지만 자세하게(?) 쓰려고 하다 보니까 글이 길어질 수밖에 없었네요. 부족한 글 읽어주셔서 감사합니다. 좋은 밤 보내세요!

8
1
심은광

심은광

사용자경험 개선을 위해 Optimistic UI를 적용 해봤습니다 !

Optimistic UI란?

Optimistic UI는 서버의 응답을 기다리지 않고, UI를 먼저 업데이트 하는 디자인 패턴입니다.

Optimistic UI를 사용하는 이유

예를 들어, 좋아요 이벤트를 생각해보겠습니다.

일반적인 경우 사용자가 좋아요를 클릭하게 되면, 프론트엔드에서는 데이터 저장을 위해 서버로 요청을 보내고 요청이 성공한 것을 확인 한 후, UI를 업데이트 해줍니다.

네트워크 환경이 원활한 경우에는 서버에 요청하는 시간이 짧아, 크게 문제가 없어 보일 것입니다.

하지만 네트워크 환경이 좋지 않은 곳에서는, 서버 요청시간이 길어지고 UI업데이트 지연이 발생해 사용자에게 렉이 걸린듯한 안좋은 경험을 줄 수 있습니다.

이러한 경험은 .. 사용자가 뒤로가기를 누르게 만들곤 하죠 ㅠㅠ..

Optimistic UI를 적용하면, 서버요청을 기다리지 않고 UI를 바로 업데이트 해주기 때문에,

UI업데이트 지연을 방지하고, 좋은 사용자 경험을 줄 수 있습니다.

저는 이번에.. 출근길 지옥철에서 저의 어플을 직접 사용해보면서.. UI지연현상이 일어나는 것을 확인하고, 고민끝에 Optimistic UI를 적용하게 되었습니다.

아래 이미지는 제 프로덕트에 Optimistic UI 를 적용하기 전,후를 비교한 영상입니다.

*테스트는 인터넷이 매우느린 Slow 3G 환경에서 진행했습니다.

Optimistic UI 적용 전 - 저장을 클릭하고 한참 뒤에, UI가 변경되는 것을 확인 할 수 있습니다.

before.gif

Optimistic UI 적용 후 - 저장을 클릭함과 동시에 UI가 업데이트 됩니다.after.gif

Optimistic UI 주의사항

Optimistic UI를 적용하게 될 경우, 데이터 성공여부를 기다리지 않기 때문에 서버와 클라이언트간에 데이터 불일치 현상이 발생 할 수 있습니다.

이러한 문제를 해소하기 위해, 데이터 요청이 실패할 경우 UI를 롤백 시키는 방법이 있긴 하지만 데이터 불일치 현상을 100% 커버할 수 있다고 보기는 어렵습니다.

그렇기 때문에 Optimistic UI 를 적용할 경우, 데이터 신뢰성과 사용자 경험개선간 트레이드오프에 대해 고민하고 선택해야 할 것 같습니다.

저는 고민끝에, Optimistic UI를 적용하게 되었는데, 여러분은 어떤 방식을 더 선호하시나요!?

모두CBT

국가고시 필답형 실기시험 준비를 도와주는 서비스입니다 .

12
0
심은광

심은광

오픈채팅봇 업그레이드 (feat. chat-gpt)

이번주 메이킹 - 오픈채팅 봇 업그레이드 !!

저는 요즘 오픈채팅 봇 만드는 재미에 빠져있습니다 :D
제가 운영하고 있는 오픈채팅방 참여자분들에게 신선한 경험을 주고 싶어서 시작한 오픈채팅 봇 만들기 프로젝트!!

처음에는 단순한 기능만 있었지만.. 생각보다 반응이 너무 좋아 이것저것 추가하다 보니 이제는 기능이 꽤나 많아졌네요!!

이번 주에는 드디어 chat-gpt를 오픈채팅 봇에 연동해 봤는데 아주 반응이 좋았습니다!
이용자분들이 굉장히 신기해하고 재밌어하셔서 개발한 보람이 있었습니다 ㅎㅎ

스크린샷 2023-08-28 오후 8.44.14.png

gpt 연동 외에도, 이것저것 집어넣다 보니 현재는 .. 날씨, 주식, 질문 등등 꽤나 많은 일을 할 수 있는 봇이 됐습니다 ㅎㅎ..

스크린샷 2023-08-28 오후 8.48.22.png

작업하면서 어려웠던 점

오픈채팅 봇을 만들 때, 핸드폰에 코드를 집어넣어야 하다보니.. 컴퓨터로 코드 작성하고 복사해서 핸드폰에 집어넣고 하는 과정이 너무 번거로웠습니다 ㅠㅠ

아직 이렇다 할 만한 해결책은 찾지 못했는데.. 연구를 계속 해봐야 할 것 같습니다.

다음 주에는 ..

이용자분들께서, 개인용 봇도 있으면 좋을 것 같다는 의견을 주셔서 제작해 보려고 합니다 ㅎㅎ

모두CBT

국가고시 필답형 실기시험 준비를 도와주는 서비스입니다 .

8
3