좋은 기회로 , 이커머스 시장에서 업체 그리고 소비자에게 만족감을 주는 서비스를 개발하는 회사 "샐러드랩" 에 4달간의 인턴기회를 얻게 되었다.
평소 트렌드에 민감하고 패션,가구등에 관심이 많았기에 이와 관련된 분야의 서비스를 개발하는 회사에서 일을 하고 싶다는 생각을 하였고 이것이 현실이 되었다.
그럼 지금부터 인턴십에 대한 이야기를 해보고자한다.
현재 10/20 일 시점으로 , 인턴을 시작한지 7주차이다.
이 시점에서 크게 위 3가지 항목에 대해 개발이야기를 할 수 있을거라고 생각된다.
먼저, 가장 인상깊었던
기존의 인턴분들, 새로운 개발 신입 분들은 모듈 설치를 학습 한뒤 , 온보딩 과제를 수행하며 "샐러드랩"의 앞으로의 개발 업무를 원활히 수행하기 위한 과정을 다졌다고 한다.
하지만, 운이 좋게(?) 온보딩 과제를 수행하기 전 인턴분이 할만한 테스크가 주어졌다고 하여 , 알파리뷰 서비스를 사용하기로 한 업체에게 보내는 "메일 서비스"를 구현해보는 기회를 가지게 되었다. 이 부분에 대해서는 나중에 여유가 생기면 차근차근 다루기로 하겠다.
메일 서비스를 구현하고 배포가 된 이후 , 본격적인 "샐러드랩 온보딩 과정" 을 수행해보게 되었다.
먼저, 인턴십을 하기 전 백엔드에 대한 무서움, 나와는 거리가 먼 것이라는 생각을 가지고 있었고 프론트엔드는 공모전 및 프로젝트를 진행할떄 맡아보면서 그래도 친밀감이 있는 분야였다.
"온보딩 과정" 은 Todo list 구현인데 , 프론트엔드 그리고 백엔드까지 전체적인 웹 개발을 해야하는 것이었다. TODDLIST 라는 것이 예전에 react에 입문을 하려고 했을때나 어떠한 것을 보더라도 구글에 예시로 많이 언급되는 분야인만큼 친밀감이 있었고 , 어렵게(?) 느껴지지는 않았다.
하지만, 그러한 생각은 오만이었고 개발을 잘 몰랐기에 할 수 있었던 생각이라고 말할 수 있겠다.
saladlab - todolist onboarding
- django
- Angular
현재 인턴으로 배정된 개발팀에서 서비스하고 있는 "국내 알파리뷰"는 django , angular 를 사용하여 웹개발을 한다. 그렇기에 이번 온보딩 과정에서 사용한 프레임워크는 장고와 앵귤러였다.
"장고" , "앵귤러"
장고는 백엔드에서 java/spring이 있다면 python/django 도 존재한다란 식으로 얼추 알고 있었으며 간단하게 사용해보았었다.
앵귤러는 정말 생소했고 생소했다.
그럼, 이러한 내가 온보딩 과정을 어떻게 진행하였고 해쳐나가보았는지에 대해서 자세하게 다뤄보고자 한다.
<항해 1 일차>
먼저, "샐러드랩" 에서 신입분들 그리고 인턴분들이 온보딩 과정을 수행하는 첫 시작이 원활하도록 아주 기본적인 파일이 구성된 폴더를 깃허브로 올려놓아 주셨다.
그렇기에 git에서 clone을 진행하여 로컬로 폴더를 가져와주었다.
git clone url,
git branch myname
git checkout myname
git pull origin main (*기존것 당겨오기)
django
#1. 가상환경 구축
python -m venv 가상환경이름
cd scrpits
activate (*가상환경 실행)
#2. 서버 가동 및 확인
python manage.py runserver
#3. 기능 및 역할
from django.urls import include, path
urlpatterns = [
path('api/', include([
path('todo/', include('todo.urls')),
path('admin/', admin.site.urls),
path('user/', include('user.urls') )
])),
]
상위 root로 api/
그 아래로 admin/ , todo/ , user/ 가 위치하고 있다
admin/
1. 장고의 자동관리 인터페이스
2.이번 온보딩에서는 크게 쓰임이 없다
todo/
1. todo에 관련된 tododb,todoviews를 관리하는곳
2. 가장 많은 동작이 이루어지는 곳이라고 해도 될것같다 .
#개발하는 웹이 todo웹이다 보니
user/
1. 사용자를 관리해줘야 하는 웹이다 보니 로그인,회원가입의 동작을
처리해주는 곳
python manage.py startapp user (*django 내에서 user폴더를 생성하기 위한)
user
user/ 아래로 필요한 url들을 저장시켜놓는 곳
로그인 및 회원가입을 위한 로직이 구현되는 곳
user model이 명시되는 곳
장고에서는 로그인을 관리해주는 기능을 제공해준다고 한다.
하지만, 이렇게 하지않고 전통적인 방법으로 로그인, 회원가입을 구현하는 것을 목표로 한다.
user
- user를 관리할 수 있는 모델을 구축하기
- db - sqlite 이용
- 모델 구축 및 data가 잘 기입됬는지 확인하기
- settings.py - installed_app 에 폴더 명 기입
user.1 - model 구축
user model 명세서
id: int
user_name: str
password: str
created_at : datetime
user.2 - sqlite 이용
sqlite 를 사용하여 이번 웹개발의 데이터를 관리할 것이다
- sqlite 알맞은 버전 다운로드
- manage.py 와 동일한 레벨의 경로에 설치
- settings.py - DATABASES
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }
user.3 - 모델 구축 및 data가 잘 기입됬는지 확인
migrate 사용
- python manage.py makemigrations
- python manage.py migrate (* 위 명령어까지 해야 제대로 작동이 된다)
- python manage.py dbshell (* sqlite 실행 )
- .table / .schema / select from table명 (모델이 잘 구축됬는지 확인)
user.4 - settings.py
settings.py에 기입하는 것들이 정말 중요하다고 느낀다.
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'user', 'todo', ]
위와 같이 , user , todo 의 폴더명을 기입해준다.
이렇게 , user와 관련된 로그인 & 회원가입 로직을 짜기 위한 전반적인 환경을 잡아보았다.
간략한 소감 :
온보딩을 시작하기 전 , django 튜토리얼을 보며 urls.py, views.py , models.py 가 하는 것이 무엇인지에 대해 공부를 해보았었는데 그떄 이해했던것과 직접 하나하나 코드를 적어보며 어떻게 작동하는건지 알아보고 , 선임님의 설명까지 겸하니 앞으로 이 친구들이 어떤 역할을 하는 친구들인지에 대해서 더 와닿았던 것 같다.
<항해 2 일차>
이 날은 백엔드와 프론트엔드간 통신 할 수 있는 기반을 만드는 작업을 하였다.
기존에 react를 사용해서 프론트엔드 작업을 하였을때나 해커톤에 참여했을때도 항상 백엔드와 '통신'하는 부분이 어려웠고 막혔던 경험이 있었다.
그렇기에 이번에는 꼭 나의 힘으로 이를 극복해서 자신감을 얻고 싶었다.
이떄, 임의로 데이터를 삽입해야 했기에 , user_model에서 created_at 필드 속성을 DatetimeField 에서 DateField으로 변경했다.
SQL문 사용
INSERT INTO user_user VALUES ('1' , 'JUNBO' , '1234' ,'2023-09-05')
이렇게 몇개의 데이터를 삽입해놓는다.
이를 위해, Angular 환경을 셋팅해줘야 한다.
# onboarding/front 경로에 설치
1.
npm install --save--dev @angular-devkit/build-angular
2.
ng serve
#. 부끄럽지만, 이거 한장은 첨부하고 싶었다. (끄적인 흔적)
이런식으로 구상을 하는 시간을 가지고, 유명한 todo web ,instagram등을 참고하며 디자인을 해보았다.
css
.saladlab {
font-weight: 600;
animation: heart-beat 1s ease-in-out infinite;
cursor: pointer;
}
@keyframes heart-beat {
0% {
transform: scale(1);
}
25% {
transform: scale(1.02);
}
50% {
transform: scale(1);
}
75% {
transform: scale(1);
}
100% {
transform: scale(1);
}
}
ng generate component signup(이름)
#1. Routing 을 위해
import { HomeComponent } from './home/home.component';
import { SignupComponent } from './signup/signup.component';
const routes: Routes = [
{ path: 'todo', component: TodoComponent },
{ path: 'home', component: HomeComponent },
{ path: 'signup', component: SignupComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
import { Router } from '@angular/router';
export class HomeComponent implements OnInit {
constructor(private router: Router) {}
signup() {
this.router.navigate(['/signup']);
}
<a (click)="signup()" style="color:blue; font-weight: bolder; cursor: pointer;">가입하기</a>
#2. signup - html 구축
여기서, 작업도중 css적인 요소로 마진에서 margin : top,right,bottom,left ; 순이라는 것을 알게되었다.
- 이를 위해, ngmodel을 태그에서 사용한뒤, 프론트가 값을 잘 간직하고 있는지 console.log사용해서 확인을 해보고,
<input class="inputusername" type="text" [(ngModel)]="username" placeholder="사용할 이름" />
<input class="inputpassword" type="text" [(ngModel)]="password" placeholder="사용할 비밀번호">
export class SignupComponent implements OnInit {
username = '';
password = '';
// 데이터 잘 받는지 확인하는 작업
SignupInputText() {
console.log('username :', this.username);
console.log('password :', this.password);
}
이렇게 하여 프론트에서 기입된 값이 변수에 잘 저장된 것을 확인 할 수 있었다.
더 나아가기에 앞서 , angular의 기본 이해가 필요하다 싶어 선배님에게 angular의 정석같은 설명을 듣고 angular를 이해하는데 큰 도움이 되었다.,
- angular
- 컴포넌트간에 데이터 공유 방법
- service , module, component 의 역할
- 컴포넌트간에 데이터 공유 방법
- input,outpu 데코레이터 사용
- service,module,component?
- module : 비슷한 기능별로 component를 정리할 수 있는 폴더같은 역할
- component: module안에 들어있는 component끼리는 같은 service를 사용할 수 있다.
- service는 어떠한 데서든 사용할 수 있다.
- 하지만 변수는 공유가 안된다. 같은 모듈안에 있어야만 공유가능
간략한 소감 :
앞에도 말했다 싶이 '통신'에 대해 뭔지 모를 두려움이 컸다 . 하지만 , 오늘 이를 성공하는 과정이었지만 과정속에서 스스로 이해하고 그동안 건너뛰었던게 많았다는 점을 알게되었다. 추가로, 이해를 잘 하면 할 수록 개발이 재미있어진다는 점을 느꼈다. 대충 넘기는 것은 재미도 대충일수 밖에 없다는 생각! 기대가 되었다, 서버에 프론트의 값이 들어가는 것이!
<항해 3 일차>
이날은 서버에 프론트가 던져준 데이터가 잘 들어가게끔 성공시키는 과정과 , 회원가입 로직을 구현하는 목표를 잡았다.
- Angular
- apiservice를 이용하여 , create메소드 사용
- 이떄 , angular 의 통신코드 -> subscribe() , error()
PostInputText() {
this.ApiServices.create<any>('user/signup', {
username: this.username,
password: this.password,
}).subscribe(
(json) => {
console.log('result: ', json);
this.SignupResult = json['result'];
if (this.SignupResult == '0') {
console.log('back값 확인', this.SignupResult);
alert('회원가입이 완료되었습니다. 감사합니다.');
this.gologin();
} else if (this.SignupResult == '1') {
alert('이미 사용중인 아이디입니다.');
} else if (this.SignupResult == '2') {
alert('빈 값을 채워주세요');
} else console.log('미상 에러');
// 값 저장하기 (회원가입 여부 성공 or 실패)
},
(error) => {
console.log('error');
console.log(this.username);
}
);
}
PostInputText() {
this.ApiServices.create<any>('user/signup', {
username: this.username,
password: this.password,
}).subscribe(
username , password 는 서버에게 던져줄 프론트의 값이다.
이는, body에 담겨져 있으며, ['username'] ,['password'] 를 이용하여
서버에서 사용할 수 있다.
# 통신과정 중 에러 발생
해결을 위해,
INSTALLED_APPS = [
'corsheaders',
.
.
.
]
CORS_ORIGIN_WHITELIST = ['http://127.0.0.1:4200' ,'http://localhost:4200']
# CORS_ALLOW_CREDENTIALS는 옵션
CORS_ALLOW_CREDENTIALS = True
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
APPEND_SLASH=False
이를 통해, 문제를 해결할 수 있다.
간략한 소감 :
예상치 못한 에러사항을 해결하느라 금일의 목표에는 미치지 못하였으나, 이러한 과정속에서, 보안을 위해 다른 포트의 접근을 막아주는 기본 설정값에 대해서도 알게되었고 그 외에도 부가적이지만 앞으로 꼭 필요한 요소들을 알아갈 수 있는 시간이라 의미있었다!. 에러가 발생하였을때 이를 해결하여 코드를 돌아가게 하는 것도 중요하지만, 왜 이러한 에러사항이 생기는지에 대해 알고 넘어가야 된다고 생각한다.
<항해 4 일차>
4일차, 온보딩을 진행하는 과정속에서 다른 오류사항들을 마주하게 된다.
크게,
orm이 작동하지 않는 문제
백단에서 던져주는 데이터를 프론트에서 인식을 못하는 문제
해결,
#.user/apps.py
class UserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'user'
class Usersignups(AppConfig):
name = 'usersignup'
#.user/models.py
from django.db import models
# Create your models here.
class UserSignup(models.Model):
id = models.IntegerField(primary_key=True)
user_name = models.CharField(max_length=50)
password = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
#.user/views.py
from .models import UserSignup