'개발 관심사' 카테고리의 다른 글
소프트웨어 신뢰성 선언문 (0) | 2024.03.04 |
---|---|
MSA 관련 자료집 (0) | 2022.04.13 |
웹 서비스 서버 성능 지표들 (0) | 2022.02.21 |
Gradle과 Maven (0) | 2022.02.16 |
소프트웨어 신뢰성 선언문 (0) | 2024.03.04 |
---|---|
MSA 관련 자료집 (0) | 2022.04.13 |
웹 서비스 서버 성능 지표들 (0) | 2022.02.21 |
Gradle과 Maven (0) | 2022.02.16 |
우리가 Java Spring으로 API endpoint의 Controller를 만들 때, 값을 받아올 수 있도록 Spring은 여러 방법을 지원하고 있다.
주로 함수의 파라미터 형태로 값을 받아오는 형태이다. 구체적으로 그 방식에는 아래와 같은 것들이 있다.(Annotation이 포함된 코드입니다.)
순서대로 하나씩 알아보자
http://localhost:8080/foos/abc
method의 parameter로 받아오는 코드
@GetMapping("/foos/{id}")
@ResponseBody
public String getFooById(@PathVariable String id) {
return "ID: " + id;
}
PathVariable을 사용하는 형태와 사용하지 않은 형태를 한 메소드로 둘 다 지원하는 형태다. (다형성)
http://localhost:8080/myfoos/optional/abc
----
ID: abc
http://localhost:8080/myfoos/optional
----
ID: null
method의 parameter로 받아오는 코드
required = false
를 기재해주면 id 부분이 비어 있는 url 요청도 처리 가능하다.
단, 비어있다면 id 변수는 null로 처리되니 각별히 주의가 필요하다.
@GetMapping({"/myfoos/optional", "/myfoos/optional/{id}"})
@ResponseBody
public String getFooByOptionalId(@PathVariable(required = false) String id){
return "ID: " + id;
}
?
로 쿼리임을 명시적으로 적어주고 그 뒤에 바로 변수명=값 형태로 url에 적어준다.http://localhost:8080/foos?id=abc
method의 parameter로 받아오는 코드
쿼리에 날라오는 id와 변수의 이름을 똑같이 만들어주면 String 타입 파라미터 id에 쿼리로 보낸 값이 할당 된다. (id = "abc")
@GetMapping("/foos")
public String getFooByIdUsingQueryParam(@RequestParam String id) {
return id;
}
@RequestParam(value = "searchKeyWord1", required = false) final String searchKeyWord1
@RequestParam(value = "writer", defaultValue = "MangKyu")
&&
를 사용한다.http://localhost:8080/foos?id=abc&&name=Lim
@RequestBody는 클라이언트가 전송하는 Json(application/json) 형태의 HTTP Body 내용을 Java Object로 변환시켜주는 역할을 한다.
그렇기 때문에 요청시 Body 없이 @RequestBody를 사용하는 메소드를 활용하려고 한다면 에러가 발생하게 된다.
주로 POST, PUT method를 받을 때 사용한다.
@PostMapping("/foo")
public ResponseEntity<Board> requestBody(@RequestBody final Board board) {
return ResponseEntity.ok(boardService.add(board));
}
@Getter
@Setter
public class Board {
private int index; // 게시물의 번호를 저장하는 변수
private String writer; // 작성자의 이름을 저장하는 변수
private String contents; // 작성 내용을 저장하는 변수 }
}
{
index : 1
writer: "Lim"
contents : "어쩌고저쩌고"
}
Content-Type: application/json accept-language: kor MyPin: limser
method의 parameter로 받는 코드
위의 요청을 받는 다면 language는 kor이 되겠다.
@GetMapping("/greeting")
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {
// code that uses the language variable
return new ResponseEntity<String>(greeting, HttpStatus.OK);
}
@RequestHeader로 받는 방식 몇 가지를 더 소개하고자 한다. 편한 방법을 사용하면 된다.
@RequestHeader("accept-language") String language
@RequestHeader Map<String, String> headers
@RequestHeader HttpHeaders headers
Controller에 값을 받아오고 싶은 당신도 API의 동작 설계를 고려해 용도에 맞게 사용하기를 바란다.
나를 위한 AOP 정리 (0) | 2022.03.29 |
---|---|
[Spring 레퍼런스] 8장 관점 지향 프로그래밍 (AOP) (0) | 2022.03.17 |
Spring 알고 쓰기 (시리즈 : wiki 읽으면서 모르는 거 다 찾아보기) (0) | 2022.03.11 |
close
해줘야 하는 경우 사용한다.public class Copy {
private static final int BUFFER_SIZE = 8 * 1024;
static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src);
try {
OutputStream out = new FileOutputStream(dst);
try {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
} finally {
out.close();
}
} finally {
in.close();
}
}
위의 예시코드를 try-with-resources 구문으로 바꿔보았다. 위의 코드보다는 한층 깔끔해진다.
public class Copy {
private static final int BUFFER_SIZE = 8 * 1024;
static void copy(String src, String dst) throws IOException {
try (InputStream in = new FileInputStream(src); // try-with-resources를 사용하는 부분!
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
}
}
try-with-resources의 장점
package java.lang;
public interface AutoCloseable {
void close() throws Exception;
}
package EffectiveJava.item9;
public class CustomAutoCloseable implements AutoCloseable {
public void doSomething(){
System.out.println("Do something ...");
}
@Override
public void close() throws Exception {
System.out.println("CustomResource Closed!");
}
public static void main(String[] args) {
try (CustomAutoCloseable customResource = new CustomAutoCloseable()){
customResource.doSomething();
} catch (Exception e){
e.printStackTrace();
}
}
}
// try-with-resources 구문이 끝나면서 close 메소드가 실행된다.
// Do something ...
// CustomResource Closed!
try(/* 자원 선언부 */){}
자원 선언부 자리에서 사용하여 서로 다른 2가지 이상의 에러를 일으킬 가능성이 있을 경우에 사용한다.void addSuppressed(Throwwable exception)
Throwable[] getSuppressed()
addSuppressed() // 억제된 예외를 추가
getSuppressed() // 억제된 예외(배열)를 반환
/**
* 숨겨진 에러를 만들 수 있는 suppressed를 사용하여 CustomMultipleException을 만들어보자
* 두 가지 이상 자원에 try-catch-with-resources를 사용할 때 숨겨진 에러를 찾을 수 있다.
*/
public class ThrowableGetSuppressedExample {
public static void main(String[] args) {
try {
raiseCustomMultiException();
} catch (Exception e) {
e.printStackTrace();
Throwable[] suppExe = e.getSuppressed(); // getSuppressed로 숨겨진 예외를 가져온다.
// print element of suppExe
for (int i = 0; i < suppExe.length; i++) {
System.out.println("Suppressed Exceptions:");
System.out.println(suppExe[i]);
}
}
}
/**
* @throws CustomMultiException
* IOException 속의 숨겨진(suppressed) NumberFormatException이 존재하는 형태
*/
public static void raiseCustomMultiException() throws Exception {
// creating a suppressed Exception
Exception suppressed = new NumberFormatException();
// creating a IOException object
final IOException ioe = new IOException();
// adding suppressed Exception
ioe.addSuppressed(suppressed); // 숨겨진 형태로 예외 추가
// throwing IOException
throw ioe;
}
}
java.io.IOException
at EffectiveJava.item9.try_catch_with_resources.raiseCustomMultiException(try_catch_with_resources.java:33)
at EffectiveJava.item9.try_catch_with_resources.main(try_catch_with_resources.java:13)
Suppressed: java.lang.NumberFormatException
at EffectiveJava.item9.try_catch_with_resources.raiseCustomMultiException(try_catch_with_resources.java:30)
... 1 more
Suppressed Exceptions:
java.lang.NumberFormatException
Process finished with exit code 0
최근에 Next-Step 자바지기님의 TDD, clean code 과정을 해나가면서 Spring 없이 Gradle 환경에서 Junit 5 테스트를 수행 해야 하는 일이 잦아졌다.
Gradle을 빌드하다보면 Junit 5을 dependencies에 추가했음에도 Test 메소드가 Gradle의 :test task (junit tests)를 타고 수행되지 못해 아래와 같은 에러가 뜨곤 한다.
에러의 이유는 다양하지만 그 중 junit-jupiter-engine이 테스트 코드를 인식하지 못해 에러의 원인이 되기도 한다.
Process 'Gradle Test Executor 1' finished with non-zero exit value 1
version 4.6 or higher of the build tool is installed since that is the earliest version that works with JUnit 5.
gradle -v
을 통해 확인할 수 있다.$> gradle -v
------------------------------------------------------------
Gradle 7.0.6
------------------------------------------------------------
build.gradle 파일에 Test task를 추가하면 Gradle에서 Test Task를 수행할 수 있다.
우리는 Junit 플랫폼을 사용할 것임으로 아래와 같은 코드를 build.gradle 파일에 추가해준다.
test {
useJUnitPlatform()
}
build.gradle 파일에 JUnit Dependency를 추가해준다.
본문은 아래와 같다. JUnit 5을 사용하는 것이 목적이라면 Dependencies 코드 부분까지 넘어가는 것을 추천한다.
1.1 What is JUnit 5?
Unlike previous versions of JUnit, JUnit 5 is composed of several different modules
from three different sub-projects.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
The JUnit Platform serves as a foundation for launching testing frameworks on the JVM.
It also defines the TestEngine API for developing a testing framework that runs
on the platform. Furthermore, the platform provides a Console Launcher
to launch the platform from the command line and a JUnit 4 based Runner
for running any TestEngine on the platform in a JUnit 4 based environment.
JUnit Jupiter is the combination of the new programming model and extension model
for writing tests and extensions in JUnit 5. The Jupiter sub-project provides
a TestEngine for running Jupiter based tests on the platform.
JUnit Vintage provides a TestEngine for running JUnit 3 and JUnit 4 based tests
on the platform.
결국, 우리는 JUnit의 클래스와 메소드들을 사용하기 위한 JUnit API와 Runtime Platform인 Jupiter API, 두 개의 dependency를 추가해야한다.
Build.gradle 파일에 아래와 같이 dependencies를 추가해준다.
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}
TestExample.java
를 만들어 아래 코드로 테스트 해보자.$ gradle clean test
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class TestExample {
@Test
public void testAdd() {
assertEquals(42, Integer.sum(19, 23));
}
// assertThrows 는 Throws Exception 테스트의 이전 스타일을 대체하는 JUnit5의 새로운 기능이다.
@Test
public void testDivide() {
assertThrows(ArithmeticException.class, () -> {
Integer.divideUnsigned(42, 0);
});
}
}
성공!! Test의 성공은 언제나 기분이 좋다!
build.gradle
파일의 Dependencies 부분에 아래 코드를 추가해준다.
testCompileOnly 'junit:junit:4.12'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.1'
String:: 비어있는 문자열인지 체크 하는 두 개의 메소드 비교 ( isEmpty vs isBlank ) (0) | 2021.10.25 |
---|---|
Java에서 큰 수 다루기 (BigInteger) (0) | 2021.08.05 |
Java Packages & API 사용하기 (0) | 2021.07.06 |
Java tutorial (0) | 2021.07.02 |
java.lang.String 클래스에는 비어 있는 문자열인지 체크하는 두 개의 메소드가 있습니다.
isEmpty() / isBlank() 두 메소드는 무엇이 다를까? 그 차이점을 알아보겠습니다.
length
가 0인지 체크하는 방식으로 되어 있습니다.public boolean isEmpty() {
return value.length == 0;
}
public boolean isBlank() {
return indexOfNonWhitespace() == length();
}
System.out.println("Hello".isEmpty());
// isEmpty와 isBlank 메소드 둘 다 성공한 테스트입니다.
@Test
void isEmpty(){
assertEquals("Hello".isEmpty(), false);
assertEquals("Hello ".isEmpty(), false);
assertEquals("".isEmpty(), true);
assertEquals(" ".isEmpty(), false);
assertEquals("\n\t".isEmpty(), false);
}
@Test
void isBlank(){
assertEquals("Hello".isBlank(), false);
assertEquals("Hello ".isBlank(), false);
assertEquals("".isBlank(), true);
assertEquals(" ".isBlank(), true);
assertEquals("\n\t".isBlank(), true);
}
위의 테스트 코드를 보면, 나머지 케이스는 isEmpty()와 isBlank()가 같지만,
마지막에 " ", "\n", "\t"
와 같은 공백이 있는 문자열을 체크하는 경우에는 두 메소드의 결과가 다릅니다.
isEmpty()는 문자열의 길이를 체크하여, 문자열의 길이가 0인 경우에만 true를 리턴하기 때문에 빈 공백이 들어있는 문자열은 false를 리턴합니다.
isBlank()는 문자열이 비어 있는 경우와 공백(white space)를 포함하고 있는 경우 모두 true를 리턴합니다.
끝으로, isBlank()는 Java 11 버전에 추가되었기 때문에 Java 11 버전과 그 이후 버전에서만 사용 가능합니다.
Gradle 로 Junit 5 테스트 할 수 있도록 빌드 하기 (0) | 2021.10.26 |
---|---|
Java에서 큰 수 다루기 (BigInteger) (0) | 2021.08.05 |
Java Packages & API 사용하기 (0) | 2021.07.06 |
Java tutorial (0) | 2021.07.02 |
그* 코딩테스트와 서류에 붙어 면접을 보게 되었다.
팀장님으로 보이는 시니어 한 분과 프린시플 레벨의 시니어 한 분이 들어오셨다.
굉장히 경직된 나를 보고는, 두 면접관님들이 분위기를 풀어주셔서 조금은 편하게 면접을 보았다!
실제로 나의 이력서와 한 페이지 포트폴리오를 보고 내가 익숙해진 기술과 개념에서 질문이 나왔다.
Java Spring으로 현업에서 일한 경력이 없어 물어볼 폭이 넓지 않았던 거 같고, 1년의 짧은 연구실 경력과 개인적으로 운영하는 서비스에 중심을 두고 전개 되었다.
그 후엔 내가 가진 기술 스택을 토대로 한 기술적인 사항에 대한 질문들이 들어왔다.
1. 먼저 연구실에서 데이터 플랫폼 실험을 수행한 지 질문이 들어왔다.
문제 수행력 검증과 더불어 어떤 일을 경험했는지 물어보는 듯 했다.
이 부분에서는 내가 한 일을 솔직히 말하는 것이 중요하다
2. 개인적으로 운영하는 서비스 (Java Spring)에 대해서도 질문이 들어왔다.
난 이 부분을 정말 잘 준비해 갔어야 한다.
이번 면접 기회는 개인 서비스를 통해 얻어진 느낌이었다.
개발 강의나 도서로 고민 없는 학습이 아니라 직접 부딪혀보는 야생성이 어필이 되었다고 생각한다.
내가 처한 상황과 어떻게 문제를 해결했는지, 고민을 거쳐 기술 스택을 사용했는지 잘 대답하는 것이 핵심이다.
어떻게 이 질문을 잘 대답할 지 물어본다면.. 내가 실제로 그렇게 고민하면서 개발하면 된다.
3. 졸업 후 어떤 일들을 해왔는 지
먼저 Java Spring에 관한 질문이 처음으로 나왔다.
이러한 형태의 전체 Flow와 기술적 Detail을 물어보는 질문은, 백엔드 면접뿐만 아니라 모든 면접에 해당되는, 면접자의 수준을 측정하는 질문이라고 생각한다.
Url으로 요청이 들어올 때부터 나갈 때까지 Java Spring 동작을 아는 범위에서 전부 설명해주세요.
내가 여기서 대답을 어느정도는 했지만, 추측하기로는 면접관님들이 만족하지 못하는 듯 했다.
먼저 내가 생각해보지 않았던 질문이라 답변의 포인트를 잘 잡지 못하고 횡설수설했던 탓도 있고, 워낙 방대하다보니 어느 수준에서 어떻게 대답해야할 지 갈피를 잡지 못했었다.
이 질문 이후에는 한 가지 꼬리 질문과 두 가지 추가 질문이 이어졌다.
이 후에는 DB에 관한 질문이 이어졌다. 첫 질문을 잘 대답하니 두번째로 쿼리 개선 경험을 물어보셨다.
그 이후에는 객체지향 패턴 중 하나인 싱글턴 패턴을 물어보셨고, 설명 중 class와 instance를 혼동해서 사용하는 모습에 추가 질문으로 이어졌다.
그리고 정말 기초 질문으로 마지막 검증!
이 면접 어떻게 흘러가는건가. 이런 생각에 나라도 발전할 기회로 삼자..!
마무리 단계에서는 이런 생각에 이러한 질문은 던졌다.
선배 개발자 입장에서 제가 어떤 부분을 보완하면 채용 과정에서 더 매력적인 사람이 될 지 궁금합니다!
감사하게도 두 분 다 가장 어려운 질문이라고 너털 웃음을 지으시면서도 대답을 잘해주셨다.
프린시플 시니어분
개발자를 채용할 때, 세 가지를 주로 본다고 하셨다.
그런데 경력이 적거나 없는 경우에는 다양한 문제를 만나본 적이 없고, 확연한 협업 기회도 적기 때문에 그나마 검증할 수 있는 학습능력에 주안점을 두고 면접을 진행한다고 설명해주셨다.
즉, 공부할 때 꼼꼼히 공부했는지 보는 것이다.
이는 면접시 답변이나 내가 해왔던 활동의 완성도, 그리고 프로젝트시에 다양한 고민들로 검증을 한다고 설명해주셨다.
그 전에는 공부할 때 꼼꼼히는 공부했고 프로젝트가 잘 수행 될 수 있게 공부를 해왔지만 명확한 기준이 없었다.
이 답변을 듣고 내가 보강해야 될 부분을 확연히 알 수 있었다.
팀장 포지션 시니어분
이력서와 깃허브가 가장 중요하다고 말씀해주셨다.
이력서의 경우에는 지원에 대한 성의가 나타나기 때문에, 열정이나 진심을 비추어 확인하고,
깃허브에서는 프로필과 각 프로젝트에서 사용한 언어와 프레임워크를 보고,
특히 현업에서 수행하는 Readme나 깃허브의 기능 사용 (Issue, git flow), Commit / Code convention을 지원자가 현업급으로 사용하고 있는지, 그렇지 않더라도 일관성을 지켜 코드와 커밋을 작성하는 지를 본다고 한다.
Need | Action | Explain |
말을 명료하게 하자 | 블로그든 일기는 Readme든 글을 많이 읽고 써보자 (1일 1글) |
언급하지 않았지만 횡설수설! 고쳐야된다. |
프로젝트시 기술 스택 분석 | 프로젝트에 기술을 도입하게 되면 도입 배경 글을 작성하자 | 그러자 |
면접 질문들 준비 | 면접 질문들에 모범 답변을 만들고 연습 | 학습을 더 꼼꼼하게 하자 |
이력서 | 이력서 작성 시간을 배정을 하고 항목별 메세지를 선 작성하여 채운다. |
각 항목에 담을 메세지 먼저 작성하자 |
깃허브 | IT 회사들의 깃허브를 참고하여 보강 | 깃허브는 개발자 lsmman의 얼굴이다. |
공부는 그만하자 | 원하는 기술 스택이 있다면 그에 맞는 프로젝트를 기획해서 구현해보자 | 공부가 아니라 프로젝트를 하자 |
나의 이력서 (1) | 2023.08.06 |
---|---|
[넷마블 기술 블로그] 1인분을 해내기 위한 신입의 적응기 (0) | 2022.04.08 |
프로그래밍에서 내가 이루고 싶은 것 (21.07.30 ver) (0) | 2021.07.30 |
기술 스택 정리 (0) | 2021.07.12 |
일을 재밌게 하는 법 (0) | 2021.07.01 |
들어가기 전, BigInteger Java SE 7 공식문서와 coding-factory에서 참고하여 적은 것임을 밝힙니다.
우리가 프로그램을 만들 때 조건에 의해 굉장히 큰 수의 셈이 필요한 경우가 있다. int나 long의 범위만 해도 넘을 경우가는 잘 없겠지만, 변수의 정수 표현 범위를 넘어서게 되면 0이나 내가 의도하지 않았던 값으로 출력된다. 우리는 최악의 경우를 고려해야 하므로, 무한의 정수가 들어갈 가능성이 있다면 BigInteger는 사용할 수 있는 좋은 선택지이라 하겠다.
BigInteger는 int, long, Integer, Long과 달리 문자열 형태로 숫자를 처리하므로 아무리 큰 수라도 담을 수 있다.
타입 | 범위 | 메모리 크기 (64bit 기준) | 기본/참조형 | 저장된 위치 |
int | -2,147,483,648 ~ 2,147,483,647 | 4 Byte | 기본형 | Stack |
long | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | 8 Byte | 기본형 | Stack |
BigInteger | 무한 (Infinity) | Minimum 70 Byte | 참조형 | Heap |
선언
import java.math.BigInteger;
BigInteger bigNumber = new BigInteger("10001");
사칙연산
BigInteger bigNumber1 = new BigInteger("100000");
BigInteger bigNumber2 = new BigInteger("10000");
System.out.println("덧셈(+) :" +bigNumber1.add(bigNumber2));
System.out.println("뺄셈(-) :" +bigNumber1.subtract(bigNumber2));
System.out.println("곱셈(*) :" +bigNumber1.multiply(bigNumber2));
System.out.println("나눗셈(/) :" +bigNumber1.divide(bigNumber2));
System.out.println("나머지(%) :" +bigNumber1.remainder(bigNumber2));
/*
덧셈(+) :110000
뺄셈(-) :90000
곱셈(*) :1000000000
나눗셈(/) :10
나머지(%) :0
*/
형 변환
BigInteger 클래스를 기본 타입으로 형 변환을 해야할 경우
BigInteger bigNumber = BigInteger.valueOf(100000); //int -> BigIntger
int int_bigNum = bigNumber.intValue(); //BigIntger -> int
long long_bigNum = bigNumber.longValue(); //BigIntger -> long
float float_bigNum = bigNumber.floatValue(); //BigIntger -> float
double double_bigNum = bigNumber.doubleValue(); //BigIntger -> double
String String_bigNum = bigNumber.toString(); //BigIntger -> String
2개의 수 비교
비교시엔 compareTo를 사용한다.
BigInteger bigNumber1 = new BigInteger("100000");
BigInteger bigNumber2 = new BigInteger("1000000");
int compare = bigNumber1.compareTo(bigNumber2);
우리가 알고 있는 CompareTo 리턴 값과 동일하게, 1, 0, -1로 표현된다.
BigInteger bigNumber1 = new BigInteger("50");
BigInteger bigNumber2 = new BigInteger("1000");
BigInteger bigNumber2_same = new BigInteger("1000");
int compare = bigNumber1.compareTo(bigNumber2);
System.out.println("작은 수를 큰 수랑 비교 할 때 : " + compare); // -1
int compare2 = bigNumber2.compareTo(bigNumber2_same);
System.out.println("2개의 수가 같을 때 : " + compare2); // 0
int compare3 = bigNumber2.compareTo(bigNumber1);
System.out.println("큰 수를 작은 수랑 비교할 때 : " + compare3); // 1
/*
큰 수를 작은 수랑 비교 할 때 : -1
작은 수를 큰 수랑 비교할 때 : 1
2개의 수가 같을 때 : 0
*/
Gradle 로 Junit 5 테스트 할 수 있도록 빌드 하기 (0) | 2021.10.26 |
---|---|
String:: 비어있는 문자열인지 체크 하는 두 개의 메소드 비교 ( isEmpty vs isBlank ) (0) | 2021.10.25 |
Java Packages & API 사용하기 (0) | 2021.07.06 |
Java tutorial (0) | 2021.07.02 |
실력을 늘리고 싶다면 양질전환의 법칙에 따라라.
양이 갖추어졌을 때 질은 자연스레 늘어난다.
난 내가 꿈꿔왔던 좋은 코드와 멋진 프로그래밍 설계를 내 능력으로 만드는 중이다.
내 손에 닿는 건 다 만들어보자.
닿는 걸 만들어보기 위해 필요한 기술을 찾아보고 해당 스택을 공부하는 시간도 가져보자
- Google의 Starline 3D 홀로그램 영상 통화
언제든 하고 싶은 거 생기면 적습니다.
[넷마블 기술 블로그] 1인분을 해내기 위한 신입의 적응기 (0) | 2022.04.08 |
---|---|
백엔드 기술 면접을 보고 왔다 (0) | 2021.09.09 |
기술 스택 정리 (0) | 2021.07.12 |
일을 재밌게 하는 법 (0) | 2021.07.01 |
프로그래밍에서 내가 이루고 싶은 것 (21.06.24 ver) (0) | 2021.06.24 |