01. devOps의 필요성

개발과 운영의 영역이 있다. 

개발과 운영이 상호의존적

 

 

주로 다루게 될 tool

service 중심으로 실습을 해나갈 것이다. 

02. Jira Confluence 설명

 

 

먼저 개발 프로세스를 들여다보자

코드 -> 빌드(소스를 컴파일) -> 테스트 -> 패키지(배포전 묶는 작업) -> 릴리즈 -> 모니터링 (로그 파일등..._ ) 

 

구성 도 하난의 단계로 볼 수 있다.

jira 는 협업 도구

confluence 업무 자료를 관리

Bitbucket 소스를 관리 및 수정가능 

Jenkins 소스를 파이프라인화하여 자동으로 배포할 수 있음.

03. AWS와 Docker의 필요성

AWS 와 Docker 비교하기

기존에는 IDC 를 썼다면 요즘은 클라우드 서비스로  이동했다.

 

도커로  서비스를 올릴 수 있다. 

AWS 의 장점과 단점

탄력적으로 활용가능하다.

 

작은 서비스인 경우 오히려 손해일 수도 있다. 

 

AWS 의 종류

천천히 알아가자

management 와 analysis 도 있다. 

도커의 장점

 

win10 가상환경에서 visual studio를 설치하려고 했는데 계속 설치 파일이 꺼지는 문제가 발생했다.

 

화딱지 나서 2022 , 2019 , 2017, 2015 인스톨러를 설치 했는데 똑같은 증상이었다. 

 

유투브, 구글 다 뒤져봤는데 자료가 없었다.

 

자포자기한 심정으로 microsoft store에서  검색하고 설치했더니


짜잔! 

 

설치 오류 있을때 ms store를 이용하자! 

마저 정리해보자!

[무료 프로그래밍 강의] 1시간만에 끝내는 객체지향 프로그래밍 - YouTube


6. Override

메서드 오버라이드 개념을 배워보자!

void main(){

  TimesTwo tt = TimesTwo(2);
  print(tt.calculate());

}

// method - class 내부에 있는 함수를 지칭한다. 
// override - 덮어쓰다.( 우선시 하다.)

class TimesTwo{

  final int number;

  TimesTwo(
  this.number,
  );

 // method 
 int calculate(){
   return number *2; 
 }


}

숫자를 넣으면 2배 곱 값을 주는 메서드(class 내부에 있는 함수)를 만들자

4를 리턴한다.


class TimesFour extends TimesTwo{

  TimesFour(int number)
  :super(number);

}

TimesTwo 를 extends 해서 TimesFour를 만든다.

void main(){

  TimesTwo tt = TimesTwo(2);
  print(tt.calculate());

  TimesFour tf = TimesFour(2);
  print(tf.calculate());

}

똑같이 4가 출력된다.

calculate를 부모 클래스의 메서드라서 당연히 사용가능

만약 TimesFour에서 calculate 메서드를 다르게 정의하고 싶다면?

@override 키워드를 사용한다

class TimesFour extends TimesTwo{

  TimesFour(int number)
  :super(number);

  @override
  int calculate(){
   return super.number*4;
  }

}

TimesFour 생성자에 int number를 넣으면 부모,본인 클래스에 number 가 있다. 

super를 통해서 number를 가져오고 곱하기 4 연산을 하고 넘겨주면 이제 4배 곱이 넘겨진다. 

super에도 number 가 있고 

TimesFour 본인에게도 number 있으니까 this.number 로 할 수도 있고 number로된 다른 변수가 없으니까 그냥 number 이렇게 해도 된다.

 

부모 클래스의 calculate 값을 사용하는 방식으로 override를 해보자!

class TimesFour extends TimesTwo{
  
  TimesFour(int number)
  :super(number);
  
  @override
  int calculate(){
    return super.calculate()*2;
  }

}

super의 calculate를 가져와서 또 곱하기 2해서 보내 줄 수도 있다.

 

7. Static 키워드

Static은 인스턴스에 귀속되는 것이 아닌 class 에 귀속된다. 

void main(){
  
  Employee seulgi = Employee('슬기');
  Employee chorong = Employee('초롱');
}



class Employee {
  
  // Static은 인스턴스에 귀속되는 것이 아닌 class에 귀속된다.
  static String? building;
  // 알바생 이름
  final String? name;
  
  Employee(
  this.name,
  );

  
  void printNameAndBuilding(){
  print('제 이름은 $name 입니다. $building 건물에서 근무하고 있습니다.');
  
  }
  
  static void printBuilding(){
    print('저는 $building 건물에서 근무중입니다.');
  }
  
}

이렇게  Employee 클래스를 만든다. 

name을 final 로 선언했기 때문에

이름을 변경할 수 없다. 

이런 경우 name은 인스턴스에 귀속되어있다.' 라고 표현한다. 

printNameAndBuilding을 한다면 

building 이름은 아직 안정했기 때문에 Null 이뜬다. 이런 경우도 인스턴스에 귀속되어있다고 표현.

Employee에서 building 을 초기화해보자 

class에서 building 이름을 선언했는데 인스턴스에서도 값을 공유한다.

static은 class에 귀속된다.  

8. Interface

다른 언어에서는 interface 키워드가 있지만 dart에서는 class 이름으로 구현할 수 있다. 

void main(){
  
}

class IdolInterface{
  
  String name;
  
  IdolInterface(this.name);
  
  void sayName(){
    
  }
}

class BoyGroup implements IdolInterface{
  
  String name;
  
  BoyGroup(this.name);
  
  void sayName(){}
}

IdolInterface 라는 이름으로 Interface를 만들었다. IdolInterface를 사용하는 BoyGroup.

인터페이스를 사용할때는 implements 라는 키워드를 사용한다. 안에 아무것도 선언 안하면 오류가 생긴다.

 

Missing concrete implementations of 'IdolInterface.sayName', 'getter IdolInterface.name', and 'setter IdolInterface.name'.

IdolInterface에 있는 변수와 메서드를 가져와라는 뜻이다. 

 

interface는 실제로 값을 상속하는 것이 아닌 메서드, 맴버 틀?을 제공한다고 생각하면 된다.

abstract 키워드

만약 interface를 누가 인스턴스화하고 사용한다면? 문제는 없지만 방지하는 것이 좋다. 

그럴 땐 abstract 키워드를 이용하여 interface의 instance 화를 막을 수 있다. 

abstract class IdolInterface{
  
  String name;
  
  IdolInterface(this.name);
  
  void sayName();
}

 

instance 화 할 수 없기 때문에 메서드의 바디도 지워주자 

상속받은 interface 인스턴스의 타입은 부모 인터페이스와 같은 타입이라고 뜬다.

9. Generic

타입을 외부에서 받을때 사용한다? 

이때까지 생성자의 특징은 메서드나 맴버나 타입이 미리 선언되었다는 점이다. 만약 id의 타입을 외부에서 받아서 변경하고 싶다면? 

class Lecture<T> {
  final T id;
  final String name;
  
  Lecture(this.id, this.name);
  
  void printIdType(){
    print(id.runtimeType);
  }
  
  
}

<> 꺽쇠괄호를 열고 안에 타입을 정의한다.  T는 임의로 정한 타입이름이다. 타입을 받으면 id의 타입은 T 가 된다. 

void main(){
  
  Lecture<String> lecture1 = Lecture('123','lecture1');
  
  lecture1.printIdType();
}

타입을 출력하는 printIdType 메서드를 사용하면 

String 이라고 출력된다.

10. 모든 class는 object의 extends 이다 .

 

모든 class는 4개의 메서드르 기본으로 갖고 있다. 

object의 extends 이다. 

프로젝트를 만들면서 어떻게 하면 코드를 좋게 짤까? 여러 생각이 들었다. 

그래서 1번. 남들이 만든 코드를 보고 배운다. 

2번. 기본 개념을 더 파고들자. 

 

그래서 이번 글은 dart 기본 개념 공부이다.


 

[무료 프로그래밍 강의] 1시간만에 끝내는 객체지향 프로그래밍 - YouTube

 

이번 포스팅은 영상 내용의 날먹이다. 

좋은 자료 만들어주신 '코드팩토리'님께 감사할 따름이며, 좋아요 구독 해드리자. 


1. 객체지향 프로그래밍 OOP (Object Oriented Programming)

클래스 키워드를 사용하여 프로그래밍 하는 것! 

클래스는 변수와 함수로 구성

이런 클래스들을 사용해서 인스턴스를 만들면 쉽게 아이돌을 구현할 수 있다. 

 

2. 생성자

클래스의 효율성을 비교하기 위해서 아래와 같이 예시를 만들었다. 

 

 

class Idol{
  String name = '블랙핑크';
  List <String> members = ['지수', '제니', '리사', '로제'];
  
  void sayHello(){
    print('안녕하세요 블랙핑크 입니다.');
  }
   
  void introduce(){
    print('저희 맴버는 지수,제니,리사,로제 입니다.');
  }
  
}

위처럼 블랙핑크라는 클래스 하나를 만들고,

void main() {
 Idol blackPink = Idol();
//  Idol blackPink = new Idol(); 
// dart 언어에서는 new 생성자 있는거 없는거 차이가 없다. 
 
 print(blackPink.name);
 print(blackPink.members);
 blackPink.sayHello();
 blackPink.introduce(); 
  
}

main 함수 안에서 blackPink 인스턴스를 만들었다 .

문제는 모든 인스턴스가 blackPink 똑같은 내용을 가진다. 

매개변수를 받아서 클래스를 다르게 사용할려면? 

constructor 생성자를 사용

 

클래스에서 매개변수를 받을수 있게 변경해보자

  
  Idol(String name, List<String> members)
    :this.name= name,
     this.members = members;

idol 클래스 안에 생성자를 넣는다 . 

  Idol(String name, List<String> members)
    :this.name= name,
     this.members = members;
  
  Idol(String name, List<String>members){
    this.name= name;
    this.members= members;
  }
  
  Idol(this.name, this.members);

물론 위에 생성자는 다 같은 뜻을 의미한다.

 

 

Idol 안에 매개변수를 받는다 .

여기서 this.name 에서 name은 idol 클래스의 name을 의미한다.

 

 

 

메서드에서도 매개변수 사용하기

class Idol{
  String name ;
  List <String> members ;
  
  Idol(String name, List<String> members)
    :this.name= name,
     this.members = members;
  
  
  void sayHello(){
    print('안녕하세요 ${this.name} 입니다.');
  }
   
  void introduce(){
    print('저희 맴버는 ${this.members} 입니다.');
  }
  
}

 

named Constructor 사용하기 

  Idol.fromList(List value)
    :this.name= value[0],
     this.members= value[1];

하나의 리스트로 매개변수를 받는다. 

물론 두가지 방법 같이 써도 된다. 

Immutable 프로그래밍?

요즘은 한번 값을 정하면 변하지 않는 immutable 프로그래밍을 많이 한다 .

만약 blackPink.name 이렇게 임의로 값을 변경하면 초기화된다.

fromList에서 초기한 값을 다시 초기화 시키는건 지양 해야한다. 

 

fianl 키워드를 사용한다 .

한번만 초기화 할 수 있도록! 

class Idol{
  final String name ;
  final List <String> members ;
  
//   Idol(String name, List<String> members)
//     :this.name= name,
//      this.members = members;
  
  Idol(this.name, this.members);
  
  Idol.fromList(List value)
    :this.name= value[0],
     this.members= value[1];

  void sayHello(){
    print('안녕하세요 ${this.name} 입니다.');
  }
   
  void introduce(){
    print('저희 맴버는 ${this.members} 입니다.');
  }
  
}

final은 한번 설정하면 바꿀수 없다. 

언제 선언이 될까? => 인스턴스 생성할 때!

'name' can't be used as a setter because it's final

name을 초기화 할 수 없다 ! final 로 선언했기 때문!

 

const 로 선언한다면? 

const 로 생성자를 만들거나, 그냥 생성자를 만들거나 별 차이는 없다. 

다른 점은 인스턴스를 만들때 const 로 만들 수 있다는 점! 

const Idol(this.name, this.members);

인스턴스를 const 로 만들 수 있다. 

중요한건 const는 빌드 타임 (컴파일 타임과 동의어 인지 잘모르겠습니다. ) 에 선언되기 때문에 값이 지정되 있어야한다.

만약 런 타임에 값이 정해지는 DateTime.now 같은 객체? 를 넣으면 에러가 뜬다.

arguments of a constant creation must be constant expressions.

상수 값 매개변수는 상수 표현이어야한다? 

만약 fromList 에 const 키워드를 넣으면?

Evaluation of this constant expression throws an exception.

상수 표현의 평가가 예외를 쓰로우 합니다. 

왜? 

찾아보니 array 는 빌드 타임에 메모리에 선언되고

list는 런 타임에 선언되어서 사용이 불가능하다. 

인스턴스 비교

위처럼 blackpink, blackpink2 이름으로 인스턴스를 생성해보자.

비교 해보면, 

blackpink와 blackpink2는 같습니까?: false

결과는 false 이다. 

인스턴스는 생성될 때마다 새로운 메모리에 올라간다. 

클래스는 참조형 데이터이기 때문에 값이 아니라 값을 가지고 있는 메모리 주소를 가르키기 때문

 

[Chapter 1 변수] 7. 참조형 변수(Reference Variable)의 기본개념 (tistory.com)

 

[Chapter 1 변수] 7. 참조형 변수(Reference Variable)의 기본개념

우리가 지금까지 변수에 대해서 알아보면서 중점적으로 건드렸던 것은 변수 중에서도 기본형 변수(Primitive Variable)였다. 그런데 앞서 변수의 타입에 대해서 알아볼 때 우리가 배우는 자바(Java)에

colossus-java-practice.tistory.com

여기 설명이 잘되어있다.

하지만 인스턴스를 똑같은 값으로 하고 const 로 선언했을때는 ?

blackpink와 blackpink2는 같습니까?: true가 뜬다.

매우 중요하다!  

만약 내용을 한글자라도 다르게 하면 false 가 뜬다. 

 

3. Getter and Setter 

getter

class Idol{
 String name ;
 List <String> members ;
  
 Idol(this.name, this.members);
  
 Idol.fromList(List value)
    :this.name= value[0],
     this.members= value[1];

  void sayHello(){
    print('안녕하세요 ${this.name} 입니다.');
  }
   
  void introduce(){
    print('저희 맴버는 ${this.members} 입니다.');
  }
  
  
  String get firstMember {
    return this.members[0];
  }
}

먼저 getter 를 만들어보자 .

데이터 타입, get, 메서드 명으로 

아래와 같이 간단하게 구현할 수 있다. 

setter 에서 값을 변경해야하기 때문에 final , const 키워드는 일단 다 지웠다. 

void main() {
 Idol blackPink = Idol(
 '블랙핑크',
 ['지수',' 제니', '리사', '로제'] 
 );
 
  
  print(blackPink.firstMember);

  
}

메서드이기 때문에 인스턴스명.firstMember 로 간단하게 출력할 수 있다. 

특이한건 메서드 인데 괄호를 사용하지 않는다는점. 

setter 

  String get firstMember {
    return this.members[0];
  }
  
  set firstMember(String name){
    this.members[0]= name;
  }

set, 메서드 이름, 매개변수 

매개변수는 하나만 들어간다. 

void main() {
 Idol blackPink = Idol(
 '블랙핑크',
 ['지수',' 제니', '리사', '로제'] 
 );
 
  
  print(blackPink.firstMember);
  
  blackPink.firstMember = '코코';
  print(blackPink.firstMember);
  
  
}

setter는 그냥 안에 대입 시키면 된다. 

firstmember는 코코가 된다. 

get 을 왜 쓸까 ?

  String getFirstMember(){
      return this.members[0];
  }

이렇게 메서드로 지정하고 return 하면 되는거 아닌가 ?

뭐가 다른가 ?

기능적으로 차이가 없다.

가볍게 쓸거면 getter 를 쓰고 뭐 변경하는 로직이 필요하면 메서드를 써라

 

원래 final 이면 런 타임에 선언후 변경이 되지 않는다. => setter 가 먹히지 않는다. 

하지만 list 타입은 final 이어도 최기화 후 setter 로 변경할 수 있다.

하지만 아예 members list 를 매개변수로 받아서 this.members를 초기화 할 수 는 없다. 

따라서 setter는 잘 안쓰인다 . => immutable 프로그래밍에 지양되는 행위다. 

4. private 변수 

dart에서 private 변수는 같은 dart 페이지인 경우 사용할 수 있다. 

다른 페이지에 선언된 private 값은 사용할 수 없다. 

그냥 변수 이름에 '_' d언더 스코어로 선언하면 된다.

해당 dart 파일에서 private 변수를 사용하고 싶다면 언더 스코어로 불러내면 된다. 

맴버, 메서드 다 private 기호를 사용할 수 있다. 

 

5. 상속 inheritance 

oop 의 꽃 상속을 잘해야한다. 

void main(){
  print('----Idol----');
  Idol apink = Idol(name: '에이핑크', memberCount: 5);
  
  apink.sayName();
  apink.sayMemberCount();
  
}

// 상속 - inheritance
//
// 상속을 받으면 부모 클래스의 모든 속성을
// 자식 클래스가 부여받는다 .

class Idol {
  
  String name;
  
  int memberCount;
  
  Idol({
    required this.name,
    required this.memberCount
  });
  
  void sayName(){
    print('저는 ${this.name}입니다.');
  }
  
  void sayMemberCount(){
    print('${this.name}은 ${this.memberCount}명의 맴버가 있습니다.');
  }
  
}

이렇게 idol 클래스와 인스턴스를 다시 선언하고

 

상속을 통해서 남자아이돌, 여자아이돌로 나눤보자 

idol 로부터 extends 해보자 .

일단 오류가 뜬다.

The superclass 'Idol' doesn't have a zero argument constructor. 

상위 클래스 idol 은 zero 매개변수 생성자가 없다 

곧 상속을 받으면 상위 클래스의 생성자도 똑같이 선언해줘야한다. 

 

위에서 했던 것처럼 생성자를 만들었는데 오류가 뜬다.

'memberCount' isn't a field in the enclosing class.

this.name 의 name 과  this.memberCount 의 memberCount 가 해당 필드안에서 존재하지 않는다 ? 

 

부모 클래스를 지칭하는건 this 키워드가 아니라 super 이다 .

super()는 곧 상위 클래스의 생성자를 의미한다. 

idol 생성자의 모습

idol named construtor를 이용했으니까 이 방법을 그대로 적용해서 (이름에 맞게) 생성자를 초기화해야한다. 

이렇게 생성자를 구성하면 된다.

자식 클래스 초기화 하기 

sayMembersCount는 부모 클래스에 있는 메서드이지만 상속을 했기 때문에 여기서도 사용할 수 있다.

자식 클래스에 맴버,메서드를 추가할 수 있지만 추가한 걸 부모 클래스로 올려보낼 수 없다.

sayMale 메서드를 추가해서 사용할 수 있지만 해당 메서드가 부모 클래스로 올려보내져 사용되는 일은 없다. 

 

타입 체크

부모 클래스는 오직 부모 클래스 이다.

자식 클래스는 부모 클래스 이다.

자식 클래스는 자식 클래스 이다.

 

자식 클래스는 부모,자식 클래스 둘 다 가능하다는 점! 

 

 


2부에 계속~ 

유닉스에서는 한줄이 LF(line feed)

윈도우에서는 한줄이 CRLF carriage Return 과 line fedd 로 구성 

 

따라서 git 이 헷갈려하는것 

 

git config --global core.autocrlf true

윈도우에서 위와 같이 설정하면됨 

 

참고자료'

Git 에러 CRLF will be replaced by LF (혹은 반대) 핸들링하는 방법 | 재윤 블로그 (jaeyoon.io)

'git' 카테고리의 다른 글

git login 초기화  (0) 2024.12.23

+ Recent posts