결론부터 말하면 두가지 방법이 있다. 1. X-Forwarded-For헤더에 직접 접근하여 가져오는 방법 2. HttpServletRequest의 getAddr()이 클라이언트 IP를 전달하도록 스프링 설정을 하는 방법 API를 호출한 사용자의 IP를 얻기 위해서 HttpServletRequest의 getAddr() 함수를 사용한다. 그러나 API요청이 Forward Proxy에 의해 전달 될 경우 HttpServletRequest의 getAddr() 호출 시 Forward Proxy의 IP가 찍히게 된다. 이런 경우 X-Forwarded-For라는 HTTP 헤더를 통해 프록시 서버를 통해 요청을 전달 받더라도, 진짜 Client IP를 전달 받을 수 있다. (proxy에서 X-Forwarded-For에..
서킷브레이커는 뭐고 왜 써야 하는지 짧게 정리한 글입니다. 서킷 브레이커 왜 사용 할까? Circuit Breaker 직역하자면 회로 차단기라는 뜻을 가지고 있습니다. MSA환경에서는 서비스들이 모듈로 분리되고, 요청 서비스와 응답 서비스가 있습니다. 서비스 A가 서비스 B를 호출 했을 때, 서비스 B의 상태가 비정상적이라 응답을 해줄 수 없는 경우 서비스 A는 서비스 B의 응답을 계속해서 기다리는 상태가 됩니다. 서비스 B의 장애가 서비스 A까지 전파될 수 있습니다. 이를 방지하기 위해서 서킷 브레이커를 사용합니다. 대표적인 서킷브레이커 라이브러리로는 Resilience4J가 있습니다. 요청 서비스와 제공 서비스사이에 Resilice4J를 두고 통신합니다. 서킷브레이커 패턴 서킷브레이커 패턴은 서비스 ..
Transactional 전파레벨 관련 실험 실험 환경 로컬에서 docker를 띄워 Slave, Master DB를 구성하였다. Read-Only True시 Slave DB와 연결, Read-Only False시 Master DB와 연결 하도록 구성 Transactional Read-Only False 메소드 안에서 Read-Only True인 메소드가 실행된다면? 호출 한 메소드 (Read-Only False)에서 연결 된 Master DB와의 Connection을 사용한다. 즉, 조회 쿼리 (Read-Only True)도 Slave를 찌르지 않고, Master DB와의 커넥션을 통해 가져오게 된다. Transactional Read-Only True 메소드 안에서 Read-Only False인 메소드..
타임스탬프를 RFC 3339의 형태로 보내 달라는 요구사항을 받았다. 그리고 어떤 값은 밀리세컨드 단위까지, 어떤 값은 세컨드 값 까지만 전달해 달라는 요구사항을 받았다. 어카지? ISO 8601 날짜와 시간과 관련된 데이터 교환을 다루는 국제 표준 https://ko.wikipedia.org/wiki/ISO_8601 RFC 3339 ISO 8601을 인터넷 프로토콜로 어떻게 다룰지 규정한 RFC RFC 3339에서는 'T'의 생략을 허용하지 않고, 날짜와 시간 사이의 공백을 허용한다. ISO 8601과 RFC 3339의 차이 UTC 시간대를 기준으로 여러 포맷이 사용 될 수 있지만 대부분 아래와 같은 형태 일 것이다. 2020–08–28T09:20:26.187+09:00 LocalDateTime(Loc..
컬렉션 프레임워크 란? 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합을 의미한다. 자료구조와 알고리즘을 구조화 하여 클래스로 구현해 놓은 것 구분 종류 중복 허용 순서 존재 정렬 여부 THREAD-SAFE LIST ArrayList O O X X LinkedList O O X X Vector O O X O SET HashSet X X X X Linked HashSet X O X X TreeSet X X O X MAP HashMap X X X X Linked HashMap X O X X Hashtable X X X O TreeMap X X O X List는 중복이 가능하고, 순서가 있는 데이터의 집합이다. ArrayList - 특정 원소 조회가 많은 경우 사용하는 ..
토비의 스프링 vol2 챕터 1.3 프로토타입과 스코프를 읽고 정리한 글 입니다. 스코프 존재할 수 있는 범위 빈 오브젝트가 만들어져 존재할 수 있는 범위이다. 스프링 빈은 기본적으로 싱글톤으로 만들어 진다. 애플리케이션 컨텍스트마다 빈의 오브젝트는 한 개만 만들어진다. 요청이 있을 때마다 매번 애플리케이션 로직을 담은 오브젝트를 새로 만드는 건 비효율적이기 때문이다. 하나의 빈 오브젝트에 동시에 여러 스레드가 접근하기 때문에 상태 값을 인스턴스 변수에 저장해 두고 사용할 수 없다. 싱글톤으로 설정된 빈은 DI, DL시 항상 같은 오브젝트가 리턴됨이 보장된다. DL (Dependency Lookup) : 컨테이너에서 getBean()을 통해 조회하는 것, 주입 받는 것이 아니라 직접 필요한 의존관계를 찾..
에이든의 트랜잭션 매커니즘, 샐리, 예지니어스의 트랜잭션 테코톡을 듣고 정리한 글 입니다. 트랜잭션 여러 쿼리를 논리적으로 하나의 작업으로 묶어주는 것 하나의 트랜잭션은 커밋 혹은 롤백된다. 데이터베이스에 저장된 데이터베이스의 무결성과 동시성의 성능을 지키기위해 트랜잭션의 설정이 중요 ACID 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질 Atomicity 트랜잭션은 DB에 모두 반영되거나, 전혀 반영되지 않아야 한다. 완료되지 않은 트랜잭션의 중간 상태를 DB에 반영해서는 안 된다. Consistency 트랜잭션 작업처리결과는 항상 일관성 있어야 한다. 데이터베이스는 항상 일관된 상태로 유지되어야 한다. Isolation 둘 이상의 트랜잭션이 동시 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜..
[LV.1]우아한테크코스 한달 생활기 매일 만나는 데일리 미팅 우아한테크코스는 한 명의 코치와 13~14명 정도의 크루들이 함께 데일리 미팅을 진행한다. 내가 속한 데일리 조는 매일 마스터가 정해진다. 마스터들이 대화 할 주제를 마련해 온다. 코로나때문에 온라인으로 크루들을 만나야 했다. Gather라는 가상공간과 아바타를 이용한 화상 미팅 서비스를 알게 되었다. 그렇게 우리의 모임은 Gather안에서 진행 되었다. 그곳에서 크루들이 만들어 놓은 해변가도 같이 거닐고 OX게임도 진행하였다. 첫 시작 부터 크루들을 못만나는 것이 아쉬웠었다. 그러나 Gather 덕분에 매일 아침을 즐겁게 시작할 수 있었다. 나름 대로 코로나 시국을 잘 헤쳐나가고 있었다! 연극 대신 보라 우아한 테크코스 3기에서는 "연극" ..
TCP/IP를 주제로 테코톡을 준비하였다. 네트워크를 공부할 때 각각의 계층을 따로따로 공부하는 것 보다 하나의 흐름을 통해 공부를 하면 이해가 쉬웠다. 테코톡에서도 과정을 중심으로 발표를 구성하였다.
@EnableScheduling Scheduling 관련 Bean들을 등록해 준다. @Configuration @EnableScheduling public class ScheduledConfig { } @Scheduled 메서드 위에 @Schedule 어노테이션을 붙혀 해당 로직을 스케줄링 할 수 있다. @Scheduled(cron = "0 45 20 2 * *") public String executeWithScheduled() { log.info("executeWithScheduled : 매달 2일 저녁 8시 45분"); return "execute"; } Cron표기법 초 분 시 일 월 요일 연도 0 ~ 59 0 ~ 59 0~23 1~31 1~12 0~6 생략가능 요일의 경우 0이 일요일이며 6이 ..
인수테스트시 DirtiesContext로 테스트 격리를 해주고 있다. @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) 273테스트 1min 1sec 오래 걸리는 테스트시간을 줄일 수 있는 방법이 없을 까 고민하던 중 좋은 블로그글을 발견했다..! DirtiesContext를 사용하지 않고 테스트 격리를 해서 매번 모든 Context가 새로 생성되는 비효율성을 줄일 수 있다. 테스트에서는 공유자원으로 사용되는 데이터베이스에 대한 격리가 이루어져야 하므로, TRUNCATE를 통해 데이터베이스 초기화를 시켜주는 방법으로 테스트 격리를 하는 것이다. https://newwisdom.tistory.com/95 @Dirtie..
이번 데모데이 전 까지는 정산 플로우에 대한 구현이 주요 이슈가 되었다. 정산 플로우를 어떻게 진행해야 할까.. 백엔드와 프론트의 긴 회의가 있었다. 정해진 플로우는 아래와 같다. '창작자'는 정산을 신청하기 위해 실명, 계좌번호와 통장사본과 함께 '정산 계좌 승인 요청'을 진행한다. '관리자 페이지'에서 해당 요청을 검토하고 승인, 반려한다. 승인 시 창작자는 정산을 신청할 수 있게 된다. 후원 받은 포인트는 '후원자'가 후원을 하게 되면 증가한다. 정산 가능 포인트는 '후원자'가 후원을 한 뒤 7일이 지난 뒤 증가한다. 7일 까지 후원자가 우리 서비스를 통해 환불을 진행 할 수 있기 때문이다. 정산 완료 포인트는 지금 까지 '창작자'가 정산을 요청하고 완료된 포인트이다. 이번 스프린트에서는 우아한 테..
Cloud 정확히는 인터넷을 통해 원격으로 접근할 수 있는 모든 것 인터넷으로 제공되는 서비스(메일, 드라이브 등)을 의미 Cloud Computing 서버, 데이터베이스, 네트워킹 컴퓨팅 리소스를 인터넷을 통해 관리하는 것을 의미 VPC 독립된 가상의 클라우드 네트워크 VPC는 Virtual Private Cloud의 약자로 AWS 클라우드 내 논리적으로 독립된 섹션을 제공 사용자가 정의한 가상의 네트워크상에서 다양한 AWS 리소스 실행 퍼블릭 서브넷 공인 네트워크 개념으로 외부 인터넷 구간과 직접적으로 통신할 수 있는 공공 네트워크 프라이빗 서브넷 사설 네트워크 개념으로 외부 인터넷 구간과 직접적인 통신을 할 수 없는 폐쇄적인 네트워크 통신확인하기 Ping Check IP 정보만으로 서버에 요청이 가..
비즈니스 로직과 외부라이브러리 우리 서비스는 결제모듈이 들어간다. 결제 모듈을 제공하는 서비스는 다양하다. 우리는 그중 '아임포트'라는 결제 모듈을 택했다. 그러나 우리의 비즈니스 로직에 '아임포트' 결제모듈로 특정지어서는 안된다. 외부 라이브러리와 도메인 로직이 깔끔하게 분리되길 원했다. 어댑터 패턴 Client는 써드파티 라이브러리나 외부 시스템을 사용하려는 쪽 우리 Thank you for다. Adaptee는 써드파티 라이브러리나 외부시스템 쪽 아임포트 결제모듈이다. TargetInterface.. Client는 Adaptee대신 TargetInterface를 바라봐야한다. 우리의 도메인 로직은 프론트 엔드에서 우리에게 후원하길 원하는 창작자의 페이지 이름, 후원자의 이메일, 후원 금액을 보내면 P..
와우 벌써 3주차라니. 우리팀은 2주 단위였던 스프린트를 1주 단위로 줄이고 회고하는 방식으로 변경했다. 다음 데모데이 까지 핵심기능 개발이 목표인데 좀 더 효율적으로 보인다~ 깃 서브모듈 하나의 저장소 안에 있는 또 다른 별개의 저장소 서브모듈 시작하기 Git에 팀 Operation을 만들고, Private 레포지토리를 만들었다. 해당 레포지토리를 아래 명령어로 서브모듈로 만들어준다 git submodule add {내가 서브모듈로 사용하고 싶은 레포의 URL} 서브모듈을 포함한 프로젝트 Clone 비어있다.. 아래 명령어를 실행해서 git 저장소를 초기화 해주고, 원격 저장소에서 파일을 가져온다. git submodule init git submodule update https://sgc109.git..
클라우드 인터넷을 통해서 언제 어디서든지 원하는 때 원하는 만큼의 IT리소스 (컴퓨팅, 스토리지, 네트워크)를 손쉽게 사용할 수 있게하는 서비스 IaaS Infrastructure as a Service 가장 기본적인 IT 자원인 '서버, 네트워크, 스토리지' 자원을 클라우드 사업자가 제공하고 운영관리 사용자는 가상 서버에 필요한 프로그램을 설치하여 사용 및 운영 관리 EC2(컴퓨팅), VPC(네트워크), EBS(스토리지) PaaS Platform as a Service AWS Elastic Beanstalk(애플리케이션 배포) Serverless 애플리케이션 개발에 필요한 대부분을 클라우드 사업자가 제공하고 운영관리 사용자는 오직 개발에만 집중 Lambda, API Gateway SaaS Sofrwar..
배포자동화 애플리케이션을 개발하면서 feature 브랜치에서 develop 브랜치로 PR을 날리는 작업은 계속 될 것이다. 이때마다 서버로 접속하여 develop 브랜치의 소스를 pull 받고, build 하고 배포하는 작업을 해야 할까? 이럴 땐 배포자동화를 하면 된다. 젠킨스 이번 팀프로젝트에서는 배포자동화 도구로 Jenkins를 선택했다. 팀프로젝트를 시작하기 전 Jenkins를 한번 연습해 보았기도 하고 제공 되는 문서가 GitHub Actions 보다 많다. 또한 팀프로젝트 전 Jenkins를 연습할 때 프리티어 EC2에서 돌린적이 있었다. 지옥이었다. 배포자동화를 담당하는 서버는 어느정도 스펙를 갖추어야 한다고 한다. 이번 우테코 3기 팀프로젝트에서 medium 스펙의 EC2까지 생성할 수 있..
팀 결성 우아한 테크코스 레벨 3가 시작되고, 팀프로젝트를 진행하게 되었다. 나는 누구나 쉽게 창작자를 응원할 수 있는 간편 도네이션 서비스 Thank you for _ _ _프로젝트를 하게 되었다. 백엔드 4명 프론트엔드 2명이 한팀이 되어 프로젝트를 진행한다!👏 1주차에서는 팀 레포지토리가 만들어졌다. Thank you for _ _ _ 은 "창작자의 정성이 깃든 모든 저작물에 대해서 감사를 표한다" 라는 뜻을 담고 있다. 다만.. 이름이 너무 길어서 레포지토리 명은 tyf 인걸로.. 🥲 https://github.com/woowacourse-teams/2021-tyf woowacourse-teams/2021-tyf Thank You For ___ ! 누구나 쉽게 창작자를 응원할 수 있는 간편 도네이..
Naver Developers 방문 Naver Developers에 방문해서 애플리케이션 등록을 해준다. 애플리케이션 등록을 하면 Client ID와 Client Secret을 얻을 수 있다. https://developers.naver.com/docs/login/devguide/devguide.md#2-2-1-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8 네이버아이디로그인 개발가이드 - LOGIN 네이버아이디로그인 개발가이드 1. 개요 4,200만 네이버 회원을 여러분의 사용자로! 네이버 회원이라면, 여러분의 사이트를 간편하게 이용할 수 있습니다. 전 국민 모두가 가지고 있는 네이버 아 developers.naver.com 서비스 URL과 네이버아이디로그인 Call..
카카오 Developers 방문 https://developers.kakao.com/ Kakao Developers 카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다. developers.kakao.com 카카오 Developers에 방문한 뒤 애플리케이션을 추가해 준다. 카카오 로그인을 활성화 해준다. 동의 항목 관련 설정을 해준다. 발급 된 키들을 기억 해 둔다. 내 애플리케이션 > 제품설정 > 카카오 로그인 > 보안에서 Client Secret키를 발급 받는다. Client Secret 값은 절대 노출하면 안 된다. (Admin키) 인가코드 받기 카카오 로그인은 인가 코드 요청 단계에서 클라이언트에 카카오 계정..
자바 소스파일이 JVM으로 실행하는 과정 Hello.java를 생성한다. Java Compiler를 통해 Hello.class파일이 생성된다. Byte Code는 플랫폼 독립적이다. OS관계 없이 동일하다. (javac 명령어) JVM의 Java Interpreter는 Byte Code를 한줄씩 기계어로 변환하며 그때그때 실행한다. (java 명령어) ClassPath JVM이 프로그램을 실행할 때 Class 파일을 찾는데 기준이 되는 경로 InteliJ에서는 Project Structure의 Resource에서 설정가능 JIT컴파일러 란 우리가 작성한 자바 코드는 컴파일러를 통해 바이트 코드로 컴파일이 되고, 이 바이트코드는 인터프리터를 통해 한 줄 씩 기계어로 번역되어 실행이 된다고 위에서 설명하였다..
우테코에서 미션을 진행하면서 아니 왜 스프링 인터셉터에서 토큰을 검증하니 CORS 에러가 뜨면서 로그인이 안되는 거지? 이번에 사이드 프로젝트를 진행하면서 아니 왜 JsessionID가 쿠키로 안 들어오는거야? CORS와 엮이면 아니 왜부터 튀어나오게 되는데.. 이번에 정리해보자 CORS SOP 브라우저는 스크립트에서 생성된 HTTP 요청에 SOP를 적용한다. SOP란 다른 출처의 리소스를 사용하는 것을 제한 하는 보안 방식이다. URL의 프로토콜, Host, Posrt를 통해 같은 출처인지 다른 출처인지 판단 할 수 있다. CORS 추가적인 HTTP header를 사용해서 애플리케이션과 다른 Orgin의 리소스에 접근할 수 있도록 하는 매커니즘 문제적 상황 1 프론트 엔드 애플리케이션 (localhos..
클래스와 인스턴스 클래스 인스턴스를 생성하기 위한 틀 클래스 자체만으로는 상태가 없다. 클래스 메서드 인스턴스의 상태와는 관련이 없다. 인스턴스를 생성하지 않은 상태에서도 호출이 가능하다. 클래스 메소드는 유틸리티 메소드라고 부른다. 클래스 필드 여러 인스턴스에서 공유하는 정보가 있는 경우 사용한다. 인스턴스 단수 의미로의 객체 클래스를 통해 실체화되어 생성된다. 인스턴스는 상태를 가지며, 메서드를 통해 인스턴스의 상태가 변경된다. 인스턴스 메서드 인스턴스의 상태를 변경하거나 상태 정보를 반환할 때 사용하는 메소드 인스턴스를 생성한 후 메시지를 보낼 수 있다. 인스턴스 필드 인스턴스의 상태 정보를 가지고 있는 변수 상태변수라고도 이야기 한다. 메모리 구조 클래스 필드와 메소드 클래스 필드와 메소드는 Me..
우테코 레벨2 마지막 미션은 프론트엔드 크루들과 함께 미션을 진행하는 '협업 미션'이 주어졌다. 프론트엔드 크루들이 우리가 만든 서버를 사용할 수 있도록 배포를 해야 했다. 이번 포스팅에서는 협업미션을 하면서 AWS, nginx, HTTPS를 적용하여 개발환경을 구축한 것을 정리해 보려고 한다. 서버 생성 서버로 사용 할 EC2를 만든다. EC2는 AWS로 부터 컴퓨터 한대를 임대해서 사용 할 수 있는 서비스 EC2를 생성했다면 EC2서버에 접속해서 환경을 꾸린다. EC2에 도커 설치 $ sudo apt-get update && \ sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common && \ ..
목적 이전 미션의 PR들을 보고 있다. 레벨 2가 끝나가는 시점에 잘 지켜지는 피드백도 있고, 그렇지 않은 피드백도 있다. 잘 이해가 되는 개념도 있고 그렇지 않은 개념도 있다. 그런 것들을 정리해 보려고 한다. 객체를 객체스럽게 사용해라 이번 지하철 미션에서도 한번 피드백을 받았다. 한번 더 리마인드 하면 좋을 것 같다. Line line = findById(id); Sections sections = line.getSections(); List deleteSections = sections.deleteSection(stationId); Line line = findById(id); List deleteSections = line.deleteSection(stationId); 객체는 캡슐화된 상태와 외..
도커는 너무 어려워요 우아한테크코스 Level2에서 배포하기라는 큰 산을 만났다. 가이드 대로 따라하면 동작하기는 했지만 명령어가 무슨 의미인지 모르고 진행하니 답답했다. 이번 포스팅에서는 도커에 대한 간단한 설명과 배포하기를 하면서 만난 도커 명령어의 의미를 정리해 볼 것이다. 도커를 왜 사용 할까? snowflak server 이슈 스노우 플레이크 서버 한번 설치한 서버에 계속해서 설정을 변경하고 패치를 적용하는 등의 업데이트를 지속적으로 적용하여 운영하는 서버 스노우 플레이크 서버는 다시 똑같이 설정하기가 매우 어렵다. 장비를 업그레이드 하거나 OS를 새로 인스톨해서 같은 환경을 꾸미고자 할 때 예전 환경과 동일한 환경을 구성하기가 어렵다. 이미지와 컨테이너 도커를 사용하면 개발 환경을 이미지화 시..
Optional null을 대신 하도록 자바 8에서 추가된 코어 자바 라이브러리 데이터 형식 Optional 왜 쓸까 null을 사용하게 되면 NPE가 발생 null인 변수를 참조하면 프로그램이 즉시 종료 Optional을 사용하면 개발자가 변수에 값이 있는지 없는지 체크가능 리턴 값이 없을 수 있다는 사실을 Optional을 통해 문서화 한다. Optional 어떻게 쓸까 of() 팩토리 메서드로 Optional 인스턴스를 만든다. get()으로 안에 있는 값을 꺼낼 수 있다. Optional a = Optional.of("a"); assertEquals("a", a.get()); 그러나 get()으로 얻어오는 경우 값이 없다면 NoSuchElementException을 발생시킨다. null 이건 em..
책임과 메시지 자율적인 책임의 특징은 객체가 어떻게 해야 하는가가 아니라 무엇을 해야하는가를 설명한다는 것이다. 객체지향 공동체를 구성하는 기본 단위는 '자율적'인 객체다 객체들은 애플리케이션의 기능을 구현하기 위해 협력한다. 협력 과정에서 각자 맡은 바 책임을 다하기 위해 자율적으로 판단하고 행동한다. 책임들은 객체를 자율성을 침해하지 않을 정도로 추상화 되어야 한다. 추상적이고 포괄적인 책임은 협력을 좀 더 다양한 환경에서 재사용 할 수 있도록 유연성이라는 축복을 내려준다. 그러나 책임은 협력에 참여하는 의도를 명확하게 설명할 수 있는 수준 안에서 추상적이어야 한다. 다형성 이란 서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다르게 반응하는 것을 의미한다. 서로 다른 객체들이 다형성을 만족시키는..
브라우저에서 google.com를 요청할 때 통신 과정이 어떻게 이루어질까요? 그러게요...? 이제 알아봅시다. 1. 브라우저에 google.com을 입력한다. 우리는 하이퍼텍스트를 주고받을 수 있는 WWW라는 서비스를 사용할 것입니다. WWW서비스의 클라이언트가 되는 브라우저를 사용할 것입니다. http://www.google.com은 google의 www 서버(웹서버)를 가리킵니다. http는 www 서비스를 나타냅니다. www서비스는 HTTP 프로토콜을 사용합니다. 2. 브라우저는 DNS 프로토콜을 사용하여 www.google.com의 IP주소를 얻어온다. nslookup 이라는 명령어를 통해 www.google.com의 실제 IP를 볼 수 있습니다. 저의 경우 142.250.76.142가 나옵니다..
Dependency Injection 의존 주입 한 클래스가 다른 클래스의 메서드를 실행할 때 이를 '의존'한다고 한다. 의존은 변경에 의해 영향을 받는 관계를 의미한다. 의존 주입은 의존하는 객체를 직접 생성하는 대신 의존 객체를 전달받는 방식을 사용 변경에 유연해 질 수 있다. public MemberRegisterService(MemberDao memberDao) { this.memberDao = memberDao 객체를 생성하고 의존 객체를 주입하는 것은 스프링 컨테이너 설정 파일을 정의한 후 AnnotationConfigApplicationContext를 이용해서 스프링 컨테이너를 생성해야 한다. 스프링 컨테이너로 부터 getBean()을 사용하여 Bean 객체를 얻어올 수 있다. @Config..
Web Server, Web Application 웹서버 HTTP Server(아파치) URL 및 HTTP를 이해하는 소프트웨어 저장하는 웹 사이트의 도메인 이름을 통해 액세스 할 수 있으며 이러한 호스팅 된 웹사이트 콘텐츠를 최종 사용자의 장치로 전달 정적타입(HTML, CSS, 이미지등)의 데이터만 처리 -> jsp파일이라면? 톰캣 WAS (Web Application Server) 스프링의 내장 WAS가 톰캣이다. JSP와 Servelt, 스프링 MVC을 구동하기 위한 서블릿 컨테이너 역할을 수행한다. 아파치서버와는 다르게 DB연결, 다른 응용프로그램과 상호 작용 등 동적인 기능 사용가능 자바코드를 컴파일하여 html파일로 만들어 준다. 서블릿 Servlet 클라이언트의 요청을 받고 요청을 처리하여..
어떤 어노테이션 들이 있을까 @NotNull 어노테이션이 붙은 프로퍼티가 Null이 아닌지 검증한다. @NotEmpty 어노테이션이 붙은 프로퍼티가 Null 이거나 빈 값인지 검증한다. String, Collection, Map, Array에 적용 될 수 있다. @NotBlank 어노테이션이 붙은 값이 Null 이거나 공백인지 체크한다. TextValue에만 적용 될 수 있다. @AssertTrue 어노테이션이 붙은 프로퍼티가 True인지 검증한다. @Size 어노테이션이 붙은 프로퍼티가 min과 max 속성 사이의 값을 가지는지 검증한다. String, Collection, Map, Array에 적용 될 수 있다. @Size(min = 10, max = 100) @Min 어노테이션이 붙은 프로퍼티가 가..
스프링은 프레임워크이다. 프레임워크 소프트웨어의 구체적인 부분에 해당하는 설계와 구현을 재사용가능 하게끔 일련의 협업화 된 형태로 클래스들을 제공하는 것 라이브러리 활용 가능한 도구들의 집합 프레임워크는 자체적인 흐름을 가지고 있어 사용자가 그에 맞춰 개발하는 것 라이브러리는 사용자의 흐름에 따라서 개발 도중 필요한 기능을 라이브러리 가져다 쓰는 것 스프링은 IoC 컨테이너를 가진다. IoC (Inversion of Controll) 제어의 역전 클래스의 관리자가 개발자가 아니라 프레임워크가 된다. 스프링이 Spring Bean을 인스턴스화 한다. 싱글톤으로 관리가 된다. 스프링은 DI를 지원한다. Spring Bean으로 등록 된 객체들의 의존성 주입이 쉬워진다. @AutoWired를 이용한 자동 의존..
우테코 체스 미션에 스프링을 도입했다. 어노테이션을 통한 의존성 주입은 신세계 였다. InteliJ에서 노란줄을 띄웠음에도 필드 주입을 주로 사용했다. (간결해..!) 리뷰어 분께서 필드 주입에 관해서 피드백을 주셨다. 이번 포스팅은 피드백 주신 대로 필드 주입이 무엇인지, 왜 권장하지 않는지, 대안은 무엇인지 학습해 볼 것이다. 필드 주입 이란 @Autowired를 필드에 직접 사용하는 경우를 필드 주입이라고 한다. @AutoWired private ChessService chessService; 왜 필드 주입을 권장하지 않는가? 순환참조 A가 B를 참조하고, 다시 B가 A를 참조하는 경우를 말한다. class A { @Autowired private B b; public void do() { b.do..
우테코에서 스프링을 공부하면서 아래 내용을 참고하여 정리한 글 입니다. docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-requestmapping Web on Servlet Stack Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC,” comes from the name of its source module (spring-webmvc), but it is m..
객체지향 프로그래밍 에서는 객체와 객체의 역할을 이해함으로써 코드의 유지보수성을 향상시킬 수 있습니다. 코드의 길이는 더 짧아지고, 소화하기 쉬워지며, 모듈성이 향상되고, 응집도가 높아집니다. 1.1 ) -er로 끝나는 이름을 사용하지 마세요. 클래스의 이름은 무엇을 하는지가 아니라 무엇인지에 기반 객체는 캡슐화 된 데이터의 대표자 클래스 이름이 -er로 끝난다면 이 클래스의 인스턴스는 실제로는 객체가 아니라 어떤 데이터를 다루는 절차들의 집합일 뿐 올바른 이름을 지으려면 클래스의 객체들이 무엇을 캡슐화 할 것인지 관찰 후 적합한 이름을 찾기 ex) 그는 픽셀이고 스스로 색을 바꿀 수 있어 외부에서 객체에게 그 일을 하도록 요청하면, 객체 스스로 무엇을 할 지 결정해야 함 객체는 캡슐화 된 데이터의 대표..
주말이 짧은 이유는 진짜 짧기 때문이다. 레벨1이 벌써 끝난 이유는 진짜 짧기 때문이다. 두달이다. 두달이 순식간에 지나갔다. 이 시간동안 많은 것을 했고, 많은 일들이 벌어졌다. 그리고 많이 성장했다. 값진 시간을 보냈다고 자부 할 수 있다. 레벨 1에서 수행한 미션 레벨 1의 첫 미션인 자동차 경주 미션 TDD와 MVC패턴을 적용 해 보았다. Stream에 대해 알게 되었고 처음 써 보았다....! github.com/woowacourse/java-racingcar/pull/241 [2단계 - 자동차 경주 리팩토링] 수리(이다원) 미션 제출합니다. by DWL5 · Pull Request #241 · woowacourse/ 안녕하세요! 제이 2단계 미션 제출 합니다. 1단계에서 페어 프로그래밍을 할 ..
DAO Entity Bean의 퍼시스턴스 지원 기능을 대체하는 동시에 비즈니스 로직과 퍼시스턴스 로직의 명확한 분리를 위해 퍼시스턴스 로직을 캡슐화하고 도메인 레이어에 객체 지향적인 인터페이스를 제공하는 객체를 DAO(Data Access Object) 라고 한다. DAO는 데이터 퍼시스턴트의 추상화 이다. 테이블 중심의 데이터베이스와 가깝게 고려 된다. 그래서 DAO는 데이터 베이스 테이블과 매치 된다. 데이터 CRUD를 위한 방법을 제공한다. 도메인 클래스 - User public class User { private Long id; private String userName; private String firstName; private String email; // getters and setter..
두둥 너무 어려워 보이는 SQL 미션 CRUD를 배웠기 때문에 관련 미션이 나올 거라는 착각 문제보니 여러 테이블을 짬뽕해서 데이터 추출 해야하는 느낌이듬 이제 막 CRUD를 뗀 개발자에게 너무 어려운 미션 아니오!! 미션은 요기 https://www.w3schools.com/sql/trymysql.asp?filename=trysql_func_mysql_concat 첫번째 문제 문제 파악 문제 : 200개 이상 팔린 상품명과 그 수량을 수량 기준 내림차순으로 보여주세요. OrderDeatail 테이블에 ProductId와 Quantity라는 컬럼이 존재 이것을 이용해서 같은 ProductId를 가지는 Quantitiy를 모두 더 해 200개 이상인 ProductId를 추출 어떻게 하지? 추출 된 Prod..
JDBC UPDATE @Test public void updateUserName() throws Exception { String userId = UserTest.TEST_USER.getUserId(); String updatedName = "updatedName"; userDao.updateUserName(userId, updatedName); User updatedUser = new User(userId, updatedName); User realUpdateUser = userDao.findByUserId(userId); assertEquals(realUpdateUser, updatedUser); } public void updateUserName(String userId, String name) ..
JDBC READ @Test public void findByUserId(String userId) { User user = userDao.findByUserId("userId"); assertEquals(UserTest.TEST_USER, user); } 객체 비교를 위하여 User의 hashcode, equals를 재정의 해 준다. public User findByUserId(String userId) { String sql = "select * from USERS where userId = ?"; PreparedStatement pstmt = getConnection().prepareStatement(sql); pstmt.setString(1, userId); ResultSet rs = pstmt...
데이터베이스 생성하기 CREATE DATABASE db_name DEAFAUT CHARCTER SET utf8 COLLATE utf_8general_ci; 테이블 생성하기 CREATE TABLE USERS( userIdvarchar(12) NOTNULL, passwordvarchar(12) NOTNULL, namevarchar(20) NOTNULL, emailvarchar(50), NOTNULL, PRIMARY KEY (userId) ); 데이터 CREATE INSERT INTO USERS VALUES('1', 'password', 'nickname', 'email@naver.com'); JDBC CONNECTION 자바에서 데이터베이스와 연동을 하기 위해 사용하는 표준 DAO(Data Access Ob..
LinkedList란 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식의 자료구조 노드의 포인터가 이전 노드와 다음 노드와의 연결을 담당 Node는 LinkedList에 객체를 추가하거나 삭제하면, 앞뒤 링크만 변경되고 나머지 링크는 변경되지 않음 중간에 데이터를 추가, 삭제 하더라도 전체 인덱스가 한 칸씩 뒤로 밀리거나 당겨지는 일이 없어 ArrayList에 비해 추가나 삭제가 용이 인덱스가 없어서 특정요소에 접근하기 위해서는 순차 탐색이 필요
협력하는 객체들의 공동체 클래스의 구조와 메서드가 아니라 객체의 역할,책임, 협력에 집중하라 객체지향은 객체를 지향하는 것이지 클래스를 지향하는 것이 아니다. 책임은 객체지향 설계의 품질을 결정하는 가장 중요한 요소다. 책임이 불분명한 객체는 애플리케이션의 미래 역시 불분명하게 만든다. 얼마나 적절한 책임을 선택하느냐가 애플리케이션의 아름다움을 결정한다. 자율적인 객체란 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 객체를 의미 객체는 협력 내에서 정해진 역할을 수행하며 역할은 관련된 책임의 집합이다. 객체는 다른 객체와 협력하기 위해 메시지를 전송하고, 메시지를 수신한 객체는 메시지를 처리하는 데 적합한 메서드를 자율적으로 선택한다. 객체지향의 핵심은 클래스가 아니다. 적절한 책임을 수행하는 ..
개방/폐쇄 원칙 개방 폐쇄 원칙을 적용하여 특정 메소드의 코드를 복사하거나 새 파리미터를 추가하지 않고 동작을 확장 할 수 있다. 특정 금액 이상의 모든 입출금 내역을 검색하려면? 특정 월의 모든 입출금 내역을 검색하려면? 특정 월 또는 특정 금액으로 입출금 내역을 검색하려면? 여기서는 금액을 구하는 조건을 인터페이스로 만들 수 있다. public interface BankTransactionFilter { boolean test(BankTransactino bankTransaction); } ... public List findTransactions(final BankTransactionFilter bankTransactionFilter) { fianl List result = new ArrayList..
목표 좋은 소프트웨어 개발의 기반은 무엇인가? 한개의 클래스로 구현 후 프로젝트를 진행하면서 바뀌는 요구사항이나 유지보수에 대응하며 기존 구조의 한계가 무엇인지 확인한다. 단일 책임의 원칙이란 (SRP) 응집도와 결합도의 특징 KISS 원칙 Keep it small and simple. Keep it short and simple 큰 프로젝트를 단순하게 디자인 하지 못하고 복잡하게 구현 한다는 것은 프로젝트를 제대로 이해하지 못했다는 증거이다. 프로젝트가 진행되기 전에 최대한 기반 배경과 추진되는 목적자체를 이해하고 어떻게 구현을 단순화하고 알기쉽게 설계할 수 있을지 회의를 개선해야한다. final 변수 final로 표시하면 어떤 객체의 상태가 바뀔 수 있고, 어떤 객체의 상태가 바뀔 수 없는지 명확하게..
처음 우아한 테크코스에 미션을 수행하면서 Git을 사용할 때, 헤맸던 부분에 대해서 정리하고자 한다. 우아한 테크코스의 프로그래밍 미션 수행 과정 우아한 테크코스에서 미션을 시작하면 woowacourse 저장소에 자신의 github아이디로 브랜치가 생성된다. 크루들은 미션을 진행 한 뒤, 이곳으로 PR을 보내야 한다. woowacourse의 미션 프로젝트를 자신의 계정으로 fork fork : 저장소를 자신의 계정으로 복사하는 기능 fork한 저장소를 자신의 컴퓨터로 clone clone : git 서버에 존재하는 저장소를 자신의 로컬에 복사하는 기능 기능 구현을 위한 브랜치 생성 (ex step1) 해당 브랜치에서 작업 후 add, commit, push 1단계 미션 제출 PR 보내기 PR merge ..
우아한 테크코스 3기 한 달 회고 - 벌써 LV1의 반이 지나가 버렸다. 우아한 테크코스를 시작 하기 전 "매주 마다 주간 회고를 해야지" 라고 다짐 했던 나는 어디 갔을까.. 반성을 하며 늦게나마 한달 회고를 작성해 본다. 매일 만나는 데일리 조 코치 1분에 크루 12명 정도가 데일리 조로 편성이 되었다. 코치님 왈 "호그와트 기숙사 처럼 데일리 조가 계속 유지 되는 것이 좋을 것 같다." 라고 하신 것을 보면 레벨이 바뀔 때 마다 데일리조도 재 편성이 되나보다. 우리 데일리 조는 매일 마스터가 정해져서 마스터가 대화 할 거리들을 마련해 온다. Gather에서 미팅을 하는데, 어느 순간 부터 데일리 주제들이 주로 게임이 되어버려서 아침마다 승부욕이 짱짱하게 채워질 수 있었다. Gather Gather ..
지원 "성장 할 수 있는 10개월 이다" 우아한 테크코스 속에서 보낸 10개월이 내 인생에 꾸준하게 긍정적인 영향을 미칠 것 같다는 생각이 들었다. 아니 확신이 들었다. 인트로에 나오는 문구하나하나가 성장세포를 깨우는 느낌이 들었다. 3시간 정도되는 영상을 시청하고 드는 생각은 지금 당장 바로 지원하자 였다. 그렇게 나는 우아한 테크코스 지원에 한발짝 다가가게 되었다. 코딩테스트 2020년 11월 7일 12시부터 16시 까지 4시간 동안 총 7문제를 풀었다. 나는 주로 알고리즘 공부를 할 때 사용했던 언어인 python3를 사용하여 코딩테스트를 보았다. 문제를 읽고 코드로 구현해서 해결 할 수 있는 기본능력을 보는 것 같았다. 구현을 한 뒤, 테스트 케이스가 2~3개 밖에 주어지지 않아 제출을 한 뒤에도..
안드로이드의 아키텍쳐들은 MVC, MVP, MVVM, MVI가 있지만, 이를 이루는 것에 'MV'은 필수 적으로 들어가 있다. M이란 Model, V란 View를 의미한다. View에는 사용자와 바로 인터렉션 할 수 있는 UI를 제공해주는 부분을 말한다. 안드로이드에서는 Acitivity, Fragment등 이라고 할 수 있다. 안드로이드를 처음 배우고, 아키텍처를 적용하지 않는다고 하면 이 View단에서 Data관련 로직을 처리하도록 구현하기 쉽다. 안드로이드 개발 공식 문서에서 '책임의 분리'를 강조하며 아키텍처를 사용하여 구현하는 것을 추천하는데, 이렇게 View 단에 View와 상관없는 로직을 추가하는 것은 '책임의 분리'를 적용하지 않는 것이다. 이번 포스팅에서는 안드로이드 아키텍처 스터디를 하..
implementation dependency를 추가할 때 implementation을 사용하면 테스트 소스 세트를 포함한 모든 소스 세트에서 사용 할 수 있다. testImplementation dependency를 추가할 때 testImplementation을 사용하면 test source set에서만 사용할 수 있다. androidTestImplementation dependency를 추가할 때 androidTestImplementation을 사용하면 androidTest source set에서만 사용할 수 있다.
이번에 Flutter로 앱을 출시해보려고 했는데, 안드로이드 버전코드, 버전네임을 업데이트 하는 방법에서 조금 헤메었다. 이번 포스팅에서는 그 내용을 다뤄보도록 할 것이다. 처음에 나는 local.properties에서 값을 바꿔야 한다고 생각해서 바꿔보았다. 그러나 build를 할 때 마다 값이 되돌아 오는 것이었다. 알고보니 pubspec.yaml에서 바꿔주어야 했다. version: 1.0.1+2에서 1.0.1이 version name, 2가 version code가 되겠다. pebspec.yaml 주석에도 내용이 잘 설명되어 있었다. ㅠ # The following defines the version and build number for your application. # A version num..
여러 아이템 중 하나를 고를 수 있는 콤보박스 형태의 위젯입니다. value 프로퍼티에 인스턴스들을 담은 리스트로 지정해야 합니다. 상태를 가지므로 StatefulWidget으로 작성합니다. map()함수를 사용하여 _valueList 리스트의 문자열 3개를 DropdownMenuItem인스턴스 3개로 변환했습니다. 그리고 toList() 함수를 사용하여 다시 리스트로 변환 시켜서 items 프로퍼티에 이 리스트를 지정했습니다. class _MyHomePageState extends State { final _valueList = ['첫 번째', '두 번째', '세 번째']; var _selectedValue = '첫 번째'; @override Widget build(BuildContext context..
Radio는 그룹 내에서 하나만 선택할 때 사용합닏. 그룹이 되는 항목을 열거형(enum)으로 정의하고, groupValue 프로퍼티에 열거형으로 정의한 Gender 타입의 변수를 지정하고, onChanged이벤트에서 변경된 값을 반영합니다. 현재는 ListTile을 사용했기 때문에 라디오 버튼을 터치해야 인식됩니다. enum Gender {MAN, WOMEN} class _MyHomePageState extends State { int _counter = 0; var _isChecked = false; Gender _gender = Gender.MAN; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(Bu..
CheckBox와 Switch value : 상태를 나타낼 불리언 타입의 변수 onChanged : 체크값이 변할 때 마다 발생하는데, 여기서 변경된 값이 불리언 value 인수로 넘어온다. setState() 함수를 통해 value 프로퍼티에 지정한 변숫값을 변경하며 UI를 다시 그린다. 현재 _isChecked가 CheckBox와 Switch에 동시에 사용되고 있으므로 CheckBox를 변경해도 Switch의 상태 또한 변하게 된다. var _isChecked = false; child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Checkbox( value: _isChecked, onChanged: ..
` TextField 글자를 입력받는 위젯 InputDecoration 클래스와 함께 사용하면 힌트 메시지나 외곽선 등의 꾸밈 효과 간단히 추가 가능 decoration 프로퍼티를 활용하면 다양한 효과를 줄 수 있다. labelText는 안드로이드 EditText의 hint 속성이라고 보면 된다. TextField( obscureText: true, decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Password', ), )
.idea : 개발 도구에 필요한 설정 android : 안드로이드 네이티브 코드를 작성하는 부분 ios : iOS 네이티브 코드를 작성하는 부분 lib : 다트 코드를 작성하는 부분 test : 테스트 코드를 작성하는 부분 import 'package:flutter/material.dart'; 플러터에서는 화면을 그리는 모든 디자인 요소를 위젯이라고 합니다. package:flutter/material.dart 패키지에는 머티리얼 디자인 위젯들이 포함되어 있습니다. 머티리얼 디자인을 기본으로 하는 앱은 이 패키지를 임포트하여 머티리얼 디자인 위젯을 사용할 수 있습니다. void main() => runApp(MyApp()); main() 함수는 앱의 시작점입니다. 여기서는 runApp() 함수에 MyA..
+ 연산자를 사용하면 두 리스트를 합칠 수 있다. append()를 통해 리스트에 값을 삽입할 수 있다. 해당 값은 리스트의 마지막에 삽입된다. insert를 통해 원하는 인덱스에 값을 삽입 할 수 있다. pop()을 사용하여 리스트에서 맨 마지막 값을 빼낼 수 있으며, 인덱스를 인자로 주어 해당 인덱스의 값을 빼낼 수도 있다. remove()를 사용하면 인자로 준 값을 제거 할 수 있다. 인자로 1을 주어 인덱스 0에 위치하고 있던 값 1이 제거됨을 확인 할 수 있다. index()를 사용하여 해당 값의 인덱스를 얻어 올 수 있다. 아래 코드로 5의 인덱스는 현재 a배열에서 3이라는 것을 확인 할 수 있다. max(), min()을 통해 리스트 내에서 최댓값과 최솟값을 찾을 수 있다. sort() 함수..
upper() 와 lower() find() count() 배열자르기 문자 > 아스키코드 ord() / 아스키코드 > 문자 chr()
조건문 반복문 range() 함수 3번째 인자로 준 값만큼 증가하거나 감소한다. 3번째 인자가 -1이기 때문에 1씩 감소하는 것이고, -2로 주면 2씩 감소 3을 주면 3씩 감소한다. 반대로 for i in range(0,10,2): 로 선언하게 되면 2씩 증가하게 된다. for-else 구문 for문의 break되지 않고 마지막 까지 정상 수행이 되면, else문 실행, break로 중간에 for문을 빠져나오게 된다면 else문 미실행 for i in range(1, 11): print(i) if i == 5: break; else: print(11)
변수 - 데이터를 저장 하는 공간 변수명 정하기 영문과 숫자,_로 이루어진다. 대소문자를 구분한다. 문자나 _로 시작한다. 특수문자를 사용하면 안된다 키워드를 사용하면 안된다. (if for 등) 동시에 여러 개의 변수를 선언하고, 값을 할당 할 수 있다. 파이썬 print()관련 참고 [Python]Print() Print는 가장 기본적인 Output 함수 입니다. 이번 포스팅에서는 파이썬의 Print함수에 대해 정리 해 보겠습니다. 기본사용 방법 print('Hello World!') print("Hello World!") print("""Hello World!""") print('.. devlopsquare.tistory.com 변수입력과 연산자 파이썬에서는 사용자로 부터 값을 입력받고 싶을 때 i..
Fragment Manager 액티비티 내의 프래그먼트를 관리하기 위해서는 FragmentManager를 사용해야 합니다. FragmentManager를 얻는 법은 액티비티에서 getSupportFragmentManager()를 호출하면 됩니다. 액티비티 내에 존재하는 프래그먼트를 findFragmentById()로 가져오거나 (액티비티 레이아웃 내에서 UI를 제공하는 프래그먼트의 경우) 또는 findFragmentByTag()로 가져옵니다. popBackStack()을 사용하여 프래그먼트를 백 스택에서 꺼냅니다. 백 스택에 변경 내용이 있는지 알아보기 위해 addOnBackStackChangedListener()로 리스너를 등록합니다. beginTransaction()을 이용하여 FragmentTran..
Android 앱은 액세스가 제한된 샌드박스에서 실행됩니다. 그래서 해당 샌드박스 밖에 있는 리소스나 정보를 앱이 사용해야 하는 경우에는 앱이 적절한 권한을 요청해야 합니다. 앱에 권한이 필요하다고 선언하려면 권한을 앱 manifest에 표시한 후 사용자가 런타임에 각 권한을 승인하도록 요청해야 합니다. (Android 6.0 이상) Android 6.0미만의 버전에서는 manifest.xml 파일에 을 삽입하여 권한을 추가해 주기만 하면 되었습니다. 그러나 6.0이상에서는 권한의 protection level에 따라 권한이 danger로 간주되면 사용자가 명시적으로 앱 액세스 권한을 부여해 주어야 합니다. normal로 간주된 권한은 설치 시 시스템에서 즉시 권한을 부여합니다. 현재 안드로이드에서 제공..
안드로이드 앱 삭제 했는데 데이터가 남아 있는 문제는 Android 6.0부터 제공되는 자동백업 때문입니다. 자동백업을 중지 시키려면 manifest.xml application 속성에 아래와 같은 설정을 추가해 주세요. ... ... 밑에 내용은 데이터 백업에 대한 자세한 구글 문서 입니다. 백업 사용 설정 및 중지 Android6.0(API 레벨 23) 이상을 타겟팅하는 앱은 자동으로 자동백업에 포함됩니다. 앱 manifest파일 에서 android:allowBackup에 부울 값을 설정하여 백업을 사용 설정 또는 중지합니다. 기본값은 ture이지만 의도를 명확히 나타내려면 manifest에서 다음과 같이 속성을 명시적으로 설정하는 것이 좋습니다. ... ... android:allowBackup을 ..
코틀린의 when은 자바의 swith-case를 업그레이드 한 버전이다. when (score / 10) { 6->(print('D')) 7->(print('C')) 8->(print('B')) 9,10->(print('A')) else->(print('F')) } when의 결과값을 바로 변수에 저장할 수 있다. 표현식으로 사용 할 수 있다. val grade: Char = when (score/10) { 6->'D' 7->'C' 8->'B' 9,10->'A' else->'F' } Kotlin의 경우 위와 같이 else만 있다면 if문도 표현식으로 사용이 가능하다. val value:Int = if(10 > 5) { 10 } else { 5 }
안드로이드를 다시 공부하고 있다. 가장 좋은 리소스는 구글에서 제공하는 것들 이라고 생각이 되어 구글 코드랩들을 하나씩 공부해 보려고 한다. 이번 포스팅에서는 안드로이드 Navigation에 대해 공부해 볼 것이다. Jetpack Navigation Right now you have this awesome navigation graph, but you're not actually using it to navigate. The Navigation component follows the guidance outlined in the Principles of Navigation. The Principles of Navigation recommend you use activities as entry point c..
안드로이드에서 가로화면 일때, 세로화면 일때 각각 UI가 다르다면 어떻게 대응을 할까요? 이번 포스팅에서는 안드로이드에서 화면전환에 따른 UI 대응을 하는 법에 대해 알아 보겠습니다. 예제는 다음과 같습니다. 세로화면 에서는 이미지가 보이지만 가로화면으로 전환 되었을 때는 이미지가 보이지 않도록 해보겠습니다. Android Resource Directory를 만들 때, Available Qualifiers에서 "Orientation"을 설정 할 수 있습니다. Available Qualifiers에서 "Orientation"을 선택한 뒤, ">>" 버튼을 눌러줍니다. 그리고 Resource type을 drawable로 바꾸어 줍니다. 이 예제에서는 이미지 노출 여부를 화면전화에 따라 결정 할 것이기 때문입..
sqilite3를 import 해준다. import sqlite3 Python에서 SQL문을 실행하고 나서 conn.commit()을 호출 해줘야 하는데, isolation_leve=None으로 지정해 주면 auto commit이 되어 따로 commit()을 호출 하지 않아도 된다. #DB 생성 및 Auto Commit() conn = sqlite3.connect('db파일의 경로', isolation_level=None) 데이터 삽입 #Cursor c = conn.cursor() #테이블 생성 (Data Type : TEXT, NUMERIC INTEGER REAL BLOB) c.execute("CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, user..
Print는 가장 기본적인 Output 함수 입니다. 이번 포스팅에서는 파이썬의 Print함수에 대해 정리 해 보겠습니다. 기본사용 방법 print('Hello World!') print("Hello World!") print("""Hello World!""") print('''Hello World!''') seperater 옵션 sep 인자를 사용하면 콤마로 구분된 문자열을 설정 된 값을 사용하여 결합 할 수 있습니다. print('2020','01','01', sep = '-') #출력 결과 : 2020-01-01 print('email', 'naver.com', sep='@') #출력 결과 : email@naver.com end 옵션 end 인자를 사용하면 print 함수의 마지막을 어떻게 처리 할..
Retrofit Retrofit은 Square사에서 제공하는 오픈 소스 라이브러리 입니다. REST API통신을 위한 라이브러리 입니다. 이번 포스팅에서는 Retrofit을 사용하는 방법에 대해 알아 보겠습니다. Retrofit Dependencies 추가 및 ConverterFactory Dependencis 추가 Module단의 gradle 파일에 아래와 같이 dependencies를 추가 해 줍니다. Converter로 Gson도 많이 이용하나 이번 프로젝트에서는 moshi라는 라이브러리를 사용했습니다. implementation "com.squareup.retrofit2:retrofit:2.5.0" implementation "com.squareup.retrofit2:converter-moshi:..
ViewModel과 Databinding 그리고 Recyclerview ViewModel, Databinding을 이용하여 Recyclerview를 구현 할 때, 단계적으로 어떻게 해야하는지 포스팅을 해 보았다. RecyclerView란 Recyclerview의 장점 현재 보이는 item만 처리하고 그린다. 1000개의 아이템을 가지고 있더라도 현재 보이는 10개의 아이템만 그린다. 사용자가 scroll 하면 RecylerView는 자동적으로 어떤 새로운 item이 screen에 보여져야 하는지 그리고 어떤 item이 화면에 보여주기 충분한지 결정 item이 화면에서 scroll 되면 item의 뷰가 재활용된다. item의 view는 재활용되고, 안의 data만 새로운 내용으로 채워진다. Adapter ..
안드로이드 Navigation Architecture를 사용해서 Navigation Drawer를 구현 해 볼 것이다. Navigation Architecture에는 NavigationUI클래스가 포함되어 있다. 해당 클래스에는 Top app bar, Navigation Drawer, bottom navigation 관련 메서드들이 있다. NavigationDrawer은 상단 앱바 왼쪽의 아이콘을 클릭 시 나오는 메뉴 창 이다. DrawerLayout을 추가하려면 DrawerLayout을 root로 설정해야 한다. NavigationUI는 AppBarConfiguration 객체를 사용해서 앱 상단 왼쪽의 탐색버튼을 관리한다. 기본적으로 탐색버튼은 사용자가 탐색 그래프의 최상위 대상에 있을 때 (Navi..
1. UI 정의 하기 우선 UI를 그려준다. 여기서 입력 버튼이 눌렀을 때 마다, "문제가 들어 갈 곳" , "문제 입력란", "결과가 들어 갈 곳"에서 변화가 일어나야 한다. 각 변화는 입력 값이 틀렸을 때, 맞았을 때가 다를 수 있다. 2. 데이터 바인딩 시작 우선 모듈단의 build.gradle에 DataBinding 옵션을 추가 해 주어야 한다. android { dataBinding { enabled = true } } 그 다음에는 layout_main.xml의 내용을 태그로 감싸준다. 이제는 Activity로 이동해서 Binding 객체를 만들어 준다. Binding 관련 클래스는 ActivityMainBinding으로 자동 생성 되어 있다. 해당 클래스는 태그로 선언된 XML을 위해 자동으로..
DataBinding은 ViewModel객체와 함께 사용된 LiveData와 잘 동작한다. 현재 ViewModel을 데이터 바인딩 하고 있으니 이제 LiveData를 포함 시킬 준비가 되었다. 이번 태스크에서는 GuessTheWord 앱을 LiveData를 데이터 바인딩에 사용하여 data의 변경을 UI에 알려주는 작업을 해 볼 것이다. 이렇게 되면 LiveData를 observer 메소드를 통해 감시할 필요가 없게 된다. Step 1: Add word LiveData to the game_fragment.xml file 이번 단계에서는 현재단어를 나타내는 TextView와 ViewModel의 LiveData를 바인딩 시켜 볼 것이다. 1. game_fragment.xml에서 word_text id를 가..
이전 코드랩에서 GuessTheWord App을 구현 할 때, view에 접근하기 위해 data binding을 type-safe 방식으로 사용 하였습니다. 그러나 data binding의 진정한 힘은 view 객체에 데이터를 직접 바인딩 하는 것 입니다. 이전에는 아래와 같이 binding 객체의 scoreText에 접근해서 text를 셋팅 해 주었습니다. viewModel.score.observe(this, Observer { newScore -> binding.scoreText.text = newScore.toString(); }) Current app architecture 현재 앱의 구조에 대해 살펴 보겠습니다. 앱에서 View들은 XML문서에 정의되어 있습니다. 그리고 view에 나타내기 위한..
LiveData LiveData는 Android Architecture Component중 하나이며, Observable 데이터를 가지고 있는 클래스 입니다. 또한 LiveData는 안드로이드 라이프 사이클을 인지하고 있습니다. 데이터가 업데이트 되었을 때, 자동적으로 UI를 업데이트 하기 위해 LiveData를 사용합니다. LiveData는 Observable입니다. 이것은 LiveData가 가지고 있는 데이터가 업데이트 되었을 때, activity나 fragment가 이를 인지 할 수 있다는 의미입니다. LiveData는 데이터를 가지고 있고, 이 데이터는 어떤 데이터 타입도 가능합니다. LiveData는 안드로이드 라이프사이클을 알고 있습니다. 그래서 LiveData는 STARTED, RESUME과..
1. 파이썬을 다운로드 합니다. https://www.python.org/downloads/ Download Python The official home of the Python Programming Language www.python.org 원하시는 버전을 선택하시고, 어떤 파일을 다운 받을지 선택 하세요. 설치 하실 때, Add Python version to Path 에 꼭 체크표시 해주세요! 2. VSCode를 다운로드 합니다. https://code.visualstudio.com/download Download Visual Studio Code - Mac, Linux, Windows Visual Studio Code is free and available on your favorite platf..
이번 태스크에서는 score screen에 PlayAgain 버튼을 추가 해 보겠습니다. 해당 click listener를 LiveData 이벤트를 이용해서 구현 할 것입니다. Play Again 버튼을 누르면 다시 game screen으로 이동하게 됩니다. starter code에는 이미 Play Again 버튼이 들어가 있지만 해당 버튼은 숨겨져 있습니다. 1. res/layout/score_fragment.xml에서 play_agin_button의 visibility를 visible로 바꿔주세요. 2. ScoreViewModel에서 _eventPlayAgain 이라는 Boolean값을 가지는 LiveData를 추가해 주세요. 해당 객체는 score화면에서 game화면으로 네비게이션하는 LiveDat..
이번 태스크에서는 ScoreViewModel에 있는 score 데이터를 LiveData로 변경 해 보겠습니다. 그리고 여기에 observer를 붙혀 보겠습니다. 이 태스크는 GameViewModel에서 LiveData를 적용한 것과 매우 비슷 합니다. ScoreViewModel이 완벽하게 수정되면, 이제 이 앱의 모든 데이터들이 LiveData를 사용해서 구현되게 될 것 입니다. 1. ScoreViewModel에서 score 변수를 MutableLiveData로 변경 해 주세요. score 데이터의 이름을 _score로 변경 해 주세요. 그리고 backing property를 추가 해 줍니다. private val _score = MutableLiveData() val score: LiveData get..
현재 앱은 End Game 버튼을 눌렀을 때, score screent으로 이동 합니다. 모든 단어를 다 끝마쳤을 때 또한 score screen으로 이동하도록 구현 해 보겠습니다. 사용자가 마지막 단어에 대한 문제를 끝마치면, End Game 버튼을 누르지 않더라도 자동으로 score screen으로 이동 해보도록 하겠습니다. 해당 기능을 구현하기 위해 모든 단어가 표시되었을 경우 ViewModel로 부터 Fragment에게 전달 해주는 이벤트가 있어야 합니다. 이렇게 구현 하기 위해서는 LiveData 옵져버 패턴을 이용하여 game-finished 이벤트를 모델링 해야 합니다. The Observer pattern 옵져버 패턴이란 소프트웨어 디자인 패턴 중 하나 입니다. 관찰할 수 있는 대상과 관차..
캡슐화는 오브젝트의 필드 중 일부에 대한 직접 접근을 제한하는 방법입니다. 오브젝트를 캡슐화 할 때, private 변수를 set 할 수 있는 public 메소드에 접근 할 수 있도록 합니다. 캡슐화를 사용하면 다른 클래스가 내부의 변수를 조작하는 방법을 제어 할 수 있습니다. 현재 코드는 외부 클래스가 score 데이터와 word 데이터를 value 프로퍼티에 접근 하여 수정 할 수 있습니다. (예를 들어 viewModel.score.value) 이것은 해당 코드랩에서는 문제가 되지 않지만, 프로덕션 앱에서는 ViewModel안에서 데이터를 제어 해야 할 수도 있습니다. 오직 ViewModel만 데이터를 수정할 수 있어야 하지만, UI Controller는 데이터를 읽을 수 있어야 합니다. 그래서 da..
이번 태스크는 이전 태스크와 매우 밀접하게 연관되어 있습니다. 이전 태스크에서 우리는 score과 word를 LiveData로 감싸는 작업을 하였습니다. 이번 태스크에서는 이런 LiveData에 Observer를 붙히는 작업을 해 볼 것 입니다. 1. GameFragment의 onCreateView()안에서 viewModel.score에 대한 LiveData에 Observer를 붙혀 봅시다. viewModel을 초기화 하는 코드 다음에 observe()를 사용해서 LiveData에 observer를 붙혀야 합니다. 람다 표현식을 사용하여 코드를 간단히 구현해 보세요. viewModel.score.observe(this, Observer { newScore -> }) Observer를 사용하려면 andro..
LiveData는 라이프 사이클을 인지하고, 관찰가능한 데이터를 보관하는 클래스 입니다. 예를들어 현재 score 데이터를 LiveData로 감쌀 수 있습니다. 이번 코드랩에서는 LiveData의 여러 특성들에 대해 알아 보겠습니다. LiveData는 관찰가능 합니다. 이 의미는 LiveData가 보유한 데이터가 변경되었을 때 observer에 이 변경사항이 전달 됩니다. LiveData는 데이터를 보유할 수 있습니다. LiveData는 어떤 데이터는 감쌀 수 있습니다. LiveData는 라이프사이클을 인지하고 있습니다. 현재 액티브 상태의 라이프사이클 안에서만 observer를 업데이트 합니다. 이번 태스크에서는 GameViewModel의 score 데이터 및 word 데이터를 어떻게 LiveData로..
이전 코드랩에서는 ViewModel을 사용하여 GuessTheWord 앱에서 device-configuration이 되더라도 데이터가 보존될 수 있도록 하는 작업을 하였습니다. 이번 코드랩 에서는 LiveData를 ViewModel클래스에 정합하는 방법을 배울 것 입니다. LiveData는 Android Architecture Components 중 하나이고, 기본 데이터 베이스가 변경 되었을 때, 이를 감지하여 view에 전달하는 데이터 모델을 만들 수 있도록 도와 줍니다. LiveData를 사용하기 위해서는 데이터의 변경을 감지하는 "observer"를 셋팅해야 합니다. LiveData는 lifecycle을 인지하고 있습니다. 그래서 액티브 상태인 라이프 사이클 에서의 앱 컴포넌트 옵저버만 업데이트 ..
안드로이드 앱 아키텍쳐 가이드라인은 각 역할에 맡게 클래스를 분리 하는 것을 추천 합니다. UI controller는 액티비티, 프레그먼트와 같은 UI-based의 클래스들 입니다. UI controllers는 UI 관련 로직과 운영체제와 상호작용 하는 로직(사용자의 input 캡쳐와 같은)이 들어 가야 합니다. 이곳에는 데이터들이 포함 되면 안 됩니다. 이러한 데이터는 ViewModel에서 다뤄야 합니다. ViewModel은 UI-related data를 저장하고 관리 합니다. ViewModel 클래스는 데이터가 화면 회전고 같은configuration change시 에도 남아 있도록 해줍니다. ViewModel은 안드로이드 아키텍쳐 컴포넌트 중 하나 입니다. ViewModelProvider.Facto..
사용자가 게임을 끝내고 ScoreFragment로 이동 하였을 때, 점수가 보이지 않았습니다. ScoreFragment에서 표시 할 점수를 ViewModel이 가지고 있도록 해야 합니다. 팩토리 메소드 패턴을 이용하여 뷰모델을 초기화 하는 동안 점수 값을 전달 해 봅시다. 팩토리 메소드 패턴은 팩토리 메소드를 사용하여 오브젝트를 생성하는 패턴입니다. 이 방법은 같은 클래스의 인스턴스를 반환 합니다. 이번 태스크에서는 파라미터를 전달 하여 Score Fragment와 연관이 있는 뷰모델을 생성할 것입니다. 그리고 팩토리 메소드는 뷰모델을 초기화 합니다. 1. score 패키지 안에 ScoreViewModel 클래스를 만드세요. 이 클래스는 score fragment를 위한 뷰모델이 될 것입니다. 2. Sc..
이번 태스크에서는 EndGame 버튼을 구현 할 것입니다. 1. GameFragment에서 onEndGame()버튼을 추가 해 주세요. onEndGame()메소드는 사용자가 EndGame 버튼을 눌렀을 때 호출 됩니다. 2. GameFragment의 onCreateView() 메소드 안에서 click listener를 셋팅 해 주는 코드를 작성해보세요. Got It과 Skip 버튼 아래에 binding 변수를 사용 하여 End Game에 대한 리스너를 설정 해 보세요. 3. GameFragment 안에서 score screen으로 넘어 갈 수 있도록 하는 getFinished()를 추가 해 주세요. Safe Args를 사용 하여 score 데이터를 전달 합니다. /** * Called when the g..
뷰모델은 configuration change 시에도 살아남아 있습니다. 그래서 뷰모델은 configuration change시 데이터를 보관하기에 좋습니다. 화면에 보여져야 하는 데이터와 이 데이터를 처리하는 코드를 뷰모델에 추가합니다. 뷰모델은 프레그먼트, 액티비티, 그리고 뷰와 같은 UI Controller의 참조를 가지지 않습니다. 뷰모델을 추가하기 전의 staret app과 추가한 후의 app을 비교 해 봅시다. ViewModel을 추가하기 전 : 화면 회전과 같은 Configuration Change가 일어나면 game fragment는 destroyed되고 re-created 됩니다. 이때 데이터는 사라집니다. ViewModel을 추가하고 game fragment의 데이터를 뷰모델에 옮겼을 ..
Task: Create the GameViewModel 뷰모델 클래스는 UI와 관련된 데이터들을 저장하고 관리하도록 구현 됩니다. 이 앱에서는 각 뷰모델은 각 프레그먼트들과 연관되어 있습니다. 이번 태스크에서 뷰모델을 앱에 추가 해 볼 것입니다. GameFragment를 위한 GameViewModel을 추가 해 볼 것입니다. 이 코드랩을 진행 하면서 ViewModel이 라이프 사이클을 알고 잇다는 것 또한 배우게 될 것 입니다. Step1 : Add The GameViewModel class 1. build.gradle(module:app) 파일을 열고 아래 dependencies를 추가해 줍니다. ViewModel과 관련된 dependency입니다. //ViewModel implementation 'a..
Task: Find problems in the stater app 이번 태스크에서는 GuessTheWorld starter app의 문제점을 찾아 봅시다. starter code를 실행 시켜서 Skip 또는 Got it 버튼을 누르며 게임을 진행해 보세요. 게임 스크린은 단어와 현재 스코어를 보여 줄 것입니다. 이 때, 화면을 회전 시켜보세요. 이 때 현재 점수를 잃어 버린 것을 확인 할 수 있을 것 입니다. 이번에는 게임을 진행하다가 앱을 닫았다가 다시 열어보세요. 앱 상태가 저장되지 않아 게임이 처음부터 다시 시작 되었음을 알 수 있습니다. 현재는 End Game 버튼을 누르더라도 아무일도 일어나지 않습니다. 이 앱의 문제점 해당 스타터 앱은 화면 회전과 같은 설정 변경 혹은 앱을 재시작 했을 때 ..
Task : Explore the starter code Step1 : Get Started 1. Download the GuessTheWord starter code google-developer-training/android-kotlin-fundamentals-starter-apps android-kotlin-fundamentals-starter-apps. Contribute to google-developer-training/android-kotlin-fundamentals-starter-apps development by creating an account on GitHub. github.com 코드를 다운 받은 후 안드로이드 스튜디오에서 열어주세요. 2. 앱을 에뮬레이터나 실제 핸드폰에서 한번 ..
App overView 이번 코드랩에서는 starter code로 부터 GuessTheWord app을 개발할 것 입니다. 이 앱은 두명의 플레이어가 협업하여 단어를 맞추는 게임입니다. 첫번째 플레이어는 앱에 표시된 단어를 볼 수 있습니다. 그리고 두번째 플레이어에게 그 단어를 보여주지 않고 맞추도록 어떠한 행동들을 취합니다. 두번째 플레이어는 그 단어를 추측합니다. 게임을 하기 위해, 첫 번째 플레이어는 아래의 스크린샷에 표시된 것과 같이 폰에서 앱을 열고 "기타"와 같은 단어를 봅니다. 첫 번째 플레이어는 단어 자체를 실제로 말하지 않도록 주의하면서 단어를 연상할 수 있는 행동을 합니다. 두 번째 선수가 단어를 정확하게 맞히면 첫 번째 선수가 Got It 버튼을 누르면 카운트가 한 개씩 늘어나고 다음..
이 코드랩은 안드로이드 코틀린 기초과정 입니다. 만약 이 코스를 정주행 한다면, 당신은 이 과정을 통해 많은 성과를 얻어 갈 수 있습니다. 모든 코스들은 https://codelabs.developers.google.com/android-kotlin-fundamentals/ 이곳에서 볼 수 있습니다. ViewModel과 LiveData에 대해 다루는 이 코드랩은 4개의 코드랩으로 구성되어 있습니다. ViewModel과 LiveData는 Android Architecture Components 입니다. 이것들은 당신의 앱을 좀 더 유지보수 하기 쉽고, 테스트하기 쉽게 만들어 줄 것입니다. 5.1 : ViewModel and ViewModelFactory 5.2 : LiveData and LiveData o..
사용자가 새로운 화면으로 전환 할 때 마다 안드로이드는 이를 backstack에 저장 합니다. 사용자가 이전 버튼을 누르게 되면 안드로이드는 backstack에서 현재 화면은 지워지고, backstack의 가장 위에 있는 화면으로 이동합니다. 아무 설정을 하지 않으면 사용자는 마지막으로 보았던 화면으로 이동하게 됩니다. 이전 시간에 만들었던 AndroidTrivia 앱에서는 GameOverFragment와 GameOwnFragment가 존재합니다. 여기서 이전 버튼을 누르게 되면, GameFragment로 이동하게 됩니다. 게임이 끝났기때문에, 이전 버튼을 누르면 다시 GameFragment로 이동 하지 않고, TitleFragment로 이동하게 하고 싶다면 어떻게 해야 할까요? 이번 포스팅에서는 Nav..
앱에서 사용자가 "구입하기" 버튼을 눌렀을 때, 회원가입이 되어 있다면 구매페이지로, 되어있지 않다면 회원가입 페이지로 이동해야 한다면 어떻게 구현해야 할까요? 이번 포스팅에서는 안드로이드 Navigation Component를 이용해 조건별로 화면 이동하는 방법에 대해서 알아 보겠습니다. 이번 포스팅은 이전 포스팅과 이어집니다. https://devlopsquare.tistory.com/11 안드로이드 Navigation Components로 Fragment들을 전환해 보자. Android Jetpack의 Navigation Component는 안드로이드 앱을 제작 할 때 화면간의 이동을 조금 더 쉽게 구현 할 수 있도록 도와줍니다. Navigation Component는 세 가지 주요 부분으로 구성 ..
Android Jetpack의 Navigation Component는 안드로이드 앱을 제작 할 때 화면간의 이동을 조금 더 쉽게 구현 할 수 있도록 도와줍니다. Navigation Component는 세 가지 주요 부분으로 구성 됩니다. Navigation Graph : 모든 Navigation 관련 정보가 모여있는 XML 리소스 입니다. 여기에는 대상이라고 불리는 앱 내의 모든 개별적 콘텐츠 영역과 앱에서 갈 수 있는 모든 이용가능한 path가 포함됩니다. NavHost : 탐색 그래프에서 대상을 표시하는 빈 컨테이너 입니다. 대상 구성요소에서는 프래그먼트 대상을 표시하는 기본 NavHost 구현인 NavHostFragment가 포함됩니다. NavController : NavHost에서 앱 탐색을 관리..
https://github.com/google-developer-training/android-kotlin-fundamentals-starter-apps/tree/master/AboutMeDataBinding-Starter google-developer-training/android-kotlin-fundamentals-starter-apps android-kotlin-fundamentals-starter-apps. Contribute to google-developer-training/android-kotlin-fundamentals-starter-apps development by creating an account on GitHub. github.com View에서 즉각적으로 사용 할 수 있는 Dat..
https://github.com/google-developer-training/android-kotlin-fundamentals-starter-apps/tree/master/AboutMeDataBinding-Starter google-developer-training/android-kotlin-fundamentals-starter-apps android-kotlin-fundamentals-starter-apps. Contribute to google-developer-training/android-kotlin-fundamentals-starter-apps development by creating an account on GitHub. github.com 데이터 바인딩을 사용히랴면 build.gradl..
티스토리에 코드블럭 기능을 사용하여 개발 공부를 정리를 하고 있는데, 색상이 적용이 안되어 코드들이 매우 칙칙하게 보였다. 티스토리 코드블럭에 하이라이트 적용하려면 티스토리 블로그 관리자의 "플러그인"에 들어가서 설정을 하면 된다. 플러그인에 들어가면 코드 문법 강조라는 플러그인이 있다. 이걸 사용하자. 다양한 테마들이 있는데, 나는 Xcode를 적용했다. 코드들이 훨씬 생동감(?) 있어졌다.
배열은 사용 할 때는 미리 크기를 정해서 사용 했었습니다. 집어넣어야 하는 데이터가 몇개 인지 모를 때는 Lists를 사용 합니다. val myMusician = ArrayList() myMusician.add("Micle") myMusician.add("Ann") myMusician.add("Billy") myMusician.add("Kate") 배열에서는 특정 인덱스에 접근 하려면 [] 안에 인덱스를 집어넣어 접근 하였습니다. 그러면 List에서는 어떻게 해야 할까요? List에서는 해당 작업을 위해 여러 함수를 제공 해 줍니다. //데이터를 갱신 myMusician.add(1, "Smith"); //데이터를 가져옴 println(myMusician.get(1)) 가지고 있는 리스트에서 중복을 허용하..