Building a Java Project
하나의 프로젝트는 그것과 관련된 0개 혹은 더 많은 빌더들을 가질 수 있다. 하나의 자바 프로젝트는 하나의 자바 빌더와 연관이 있다.
아래의 빌더는 다른 타입의 프로젝트와 자바 프로젝트를 구분하는 빌더이다. New 버튼의 클릭으로 자바프로젝트를 Ant builder와 연결시킬수 있다.
자바의 빌더는 자바 소스 코드를 컴파일링하고 클래스를 생성한다.
A project can have zero or more builders associated with it. A java project is associated with a java builder. To see the builders associated with a project −
- In the Package Explorer view right click on the project and select Properties.
- In the left hand side tree click Builders.
It's the java builder that distinguishes a Java project from other types of projects. By click on the New button you can associate the Ant builder with a java project. The java builder is responsible for compiling the java source code and generating classes.
Jar file 이란?
jar file 이란 여러 개의 파일을 하나로 묶어놓은 포맷 파일. 자바 환경은 컴파일러가 하나의 하드웨어에 특정화된 구조 셋을 위한 머신 코드를 생성하지 않는 다는 점에서 기타 여러 프로그래밍 환경과 구분된다. 대신에 자바 컴파일러는 자바 소스 코드를 JVM 의 약속대로 코드를 변환시키고 이것을 자바 클래스 파일이 저장한다. 클래스 파일들을 저장하기 위한 용도로도 jar 파일은 사용될 수 있다. 그러한 클래스 파일은 특정한 물리 플랫폼을 지정하지 않는 대신 자바 버츄얼 머신 아키텍쳐를 대상으로 한다.
A Java™ ARchive (JAR) file is a file format that combines many files into one. The Java environment differs from other programming environments in that the Java compiler does not generate machine code for a hardware-specific instruction set. Instead, the Java compiler converts Java source code into Java virtual machine instructions, which Java class files store. You can use JAR files to store class files. The class file does not target a specific hardware platform, but instead targets the Java virtual machine architecture.
Gradle 이란?
Gradle 이란 다중 언어 소프트웨어 개발을 위한 빌드 자동화 시스템이다. 이것은 테스트,개발, 발행을 위한 컴파일와 팩키징 속의 개발 처리를 컨트롤한다. 지원 언어는 (Kotlin, Groovy, Scala를 포함하여) 자바, C 언어 그리고 자바스크립트를 포함한다. 또한 전 세계의 소프트웨어 라이브러리의 사용에 대한 통계적 자료를 모으기도 한다.
추가 참고 자료
그래들(이하 Gradle)은 그루비(Groovy)를 기반으로 한 빌드 도구이다. Ant와 Maven과 같은 이전 세대 빌드 도구의 단점을 보완하고 장점을 취합하여 만든 오픈소스로 공개된 빌드 도구이다.
Ant
- XML 기반으로 빌드 스크립트를 작성한다.
- 자유롭게 빌드 단위를 지정할 수 있다.
- 간단하고 사용하기 쉽다.
- 유연하지만 프로젝트가 방대해지는 경우 스크립트 관리나 빌드 과정이 복잡해진다.
- 생명주기(Lifecycle)을 갖지 않아 각각의 결과물에 대한 의존관계 등을 정의해야 한다.
Maven
- XML 기반으로 작성한다.
- 생명주기(Lifecycle)와 프로젝트 객체 모델(POM, Project Object Model)이란 개념이 도입됐다.
- Ant의 장황한 빌드 스크립트를 개선했다.
- pom.xml에 필요한 라이브러리를 선언하면 자동으로 해당 프로젝트로 불러와 편리하다.
- 상대적으로 학습 장벽이 높다.
- 라이브러리가 서로 의존하는 경우 복잡해질 수 있다.
Gradle is a build automation tool for multi-language software development. It controls the development process in the tasks of compilation and packaging to testing, deployment, and publishing. Supported languages include Java (as well as Kotlin, Groovy, Scala), C/C++, and JavaScript.[2] It also collects statistical data about the usage of software libraries around the globe.
Gradle 프로젝트 구조
Gradle 관련 파일이 생성된 디렉터리에서 tree 명령어를 통해 프로젝트 구조를 확인해보자. 아래와 같은 구성을 확인할 수 있다.
$ tree
.
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── temp
│ │ └── App.java
│ └── resources
└── test
├── java
│ └── temp
│ └── AppTest.java
└── resources
build.gradle
Gradle의 기본 빌드 파일이다. 이 파일에 프로젝트의 빌드에 대한 내용을 명시한다.
gradle/wrapper/gradle-wrapper.jar
Gradle Wrapper 파일이다. gradlew 명령어로 프로젝트를 빌드 할 때 이 파일을 참조하여 설정 파일을 구성하므로 gradle build와 다르게 새로운 환경에 대한 영향이 없다.
gradle/wrapper/gradle-wrapper.properties
Gradle Wrapper 설정 파일이다.
gradlew
Unix용 실행 스크립트이다.
gradlew.bat
Windows용 실행 스크립트이다.
settings.gradle
프로젝트의 설정 정보 파일이다. 멀티 프로젝트를 구성할 때 하위 프로젝트들과의 관계를 여기서 서술해야 한다. 명시된 정보를 기준으로 프로젝트를 구성하게 된다.
src 폴더
프로젝트의 소스 폴더가 된다. src/main/java와 src/main/test 디렉터리 이름처럼 구조를 보면 maven과 동일하다.
프로젝트 구조 참고 출처 https://madplay.github.io/post/the-structure-of-the-gradle-project
상속(Inheritance)과 위임(Delegation)의 차이점
상속(Inheritance)
자바에서 상속은 하나의 클래스가 다른 하나의 클래스의 속성을 맡는 처리 과정이다. 다시 말해서 새로은 클래스들 소위 자식 클래스라고 알려진 것들은 이전에 존재하는 클래스들 즉 베이스 클래스나 수퍼 혹은 부모 클래스라고 알려진 클래스들의 속성과 행동을 넘겨받는다.
Inheritance in Java programming is the process by which one class takes the property of another other class. i.e. the new classes, known as derived or child class, take over the attributes and behavior of the pre-existing classes, which are referred to as base classes or super or parent class.
위임(Delegation)
위임은 단순히 다른 누군가에게 권한을 넘겨주는 것을 의미한다.
- 위임은 상속의 대안책이 될 수 있다
- 위임은 다른 클래스의 객체 를 하나의 인스턴스 변수로 사용한다는 것을 의미한다. 그리고 메세지들을 인스턴스로 넘겨준다.
- 이것은 사용자가 넘겨주는 각각의 메세지들에 대해 사용자가 생각해 보게 만든다는 점에서 상속보다 많은 경우에서 낫다. 왜냐하면 하나의 객체는 하나의 새로운 클래스라기 보다는 하나의 알려진 클래스 이기때문이고 이것은 사용자가 수퍼 클래스의 모든 메서드들을 받아들이도록 강요하지 않는다. : 따라서 사용자는 오직 (사용자의 관점에서) 합당한 메서드들만 공급해줄 수 잇다.
- 위임은 하나의 객체가 특정 메서드 요청을 다른 객체에게 넘겨주는 것에서 객체들 사이의 관계로 봐질 수 있으며 그것의 대리자라 부른다.
- 위임의 주요 장점은 런타임의 유동성이다. 대리자는 런타임에서 쉽게 바뀔 수 있다. 하지만 상속과는 달리 위임은 가장 인기있는 객체 지향적 언어들에게서 직접적으로 지원받지 않으며 이것은 동적 다형성을 용이하게 하지 않는다.
Delegation is simply passing a duty off to someone/something else.
- Delegation can be an alternative to inheritance.
- Delegation means that you use an object of another class as an instance variable, and forward messages to the instance.
- It is better than inheritance for many cases because it makes you to think about each message you forward, because the instance is of a known class, rather than a new class, and because it doesn’t force you to accept all the methods of the super class: you can provide only the methods that really make sense.
- Delegation can be viewed as a relationship between objects where one object forwards certain method calls to another object, called its delegate.
- The primary advantage of delegation is run-time flexibility – the delegate can easily be changed at run-time. But unlike inheritance, delegation is not directly supported by most popular object-oriented languages, and it doesn’t facilitate dynamic polymorphism.
런타임(Runtime) 이란? (런타임 시스템, 런타임 환경)
Java 런타임 환경(JRE)은 Java 프로그램이 올바르게 실행되기 위해 필요한 소프트웨어
컴퓨터 프로그래밍에서 런타임 시스템 또는 런타임 환경이란 프로그램이 생성되는 컴퓨터와 프로그램이 동작하도록 되는 컴퓨터 두 곳 모두에서 존재하는 하나의 서브 시스템이다. 그 이름은 컴파일 타임과 컴파일된 언어의 런타임에서 오는데 이것은 하나의 프로그램의 생성과 관련된 컴퓨터 프로세스들과 해당 타겟 머신에서 그것의 실행을 유사하게 구분한다.
런타임이란 프로그래밍 랭귀지 실행 모델의 몫들을 이행하는 코드의 조각이다 ( 뭔말이야...). 이것을 하는 동안 이것은 작업에 필요한 리소스들과 프로그램이 상호작용하도록한다. 런타임들은 프로그래밍 랭귀지의 필수적인 파츠이며 개별적으로 설치될 필요가 없다.
In computer programming, a runtime system or runtime environment is a sub-system that exists both in the computer where a program is created, as well as in the computers where the program is intended to be run. The name comes from the compile time and runtime division from compiled languages, which similarly distinguishes the computer processes involved in the creation of a program (compilation) and its execution in the target machine (the run time). (출처 위키백과)
Runtime is a piece of code that implements portions of a programming language's execution model. In doing this, it allows the program to interact with the computing resources it needs to work. Runtimes are often integral parts of the programming language and don't need to be installed separately.
참조, 참조 변수
이것을 알기위해서는 힙과 스택 메모리 의 개념이 나오므로 먼저 알고 가자
자바 어플리케이션은 특적한 양의 메모리가 실행을 위해 필요한데 매번 객체와 변수가 선언될 때마다 더 많은 램을 필요로한다. 단순히 선언된 모든 변수를 담고 각 메서드를 실행할 충분한 메모리를 지정해주는 것은 비효율적인 어플리케이션을 만든다.
이러한 어플리케이션 메모리 요구를 린하게(효율적이게) 유지하기 위해선 어플리케이션 메모리는 더 적은 메모리를 필요로 하는 방식으로 분할되고 어플리케이션이 더 빠르게 작동하도록 해준다.
자바 버츄얼 머신은 메모리를 자바 힙 스페이스와 오직 필요로 하는 메모리만 사용하는 스택 메모리로 나누어 준다.
Java applications need a certain amount of RAM on a computer to run. Each time an object or variable is declared, it needs more RAM. Simply designating enough memory to hold every value declared and run each method would lead to a bloated application.
To keep application memory requirements lean, it is partitioned in ways that require less memory and allows the application to run more quickly.
The Java Virtual Machine (JVM) divides memory between Java Heap Space and Java Stack Memory in a way that only uses memory that’s needed.
힙 (Heap Space)
동적메모리. 기본타입과 달리 크기가 정해져있지않고 프로그램 실행시 메모리에 동적으로 할당한다.
지속적으로 살아남은(계속 사용되는) 객체메모리를 저장하는 올드제너레이션과 새로 생성된 객체를 저장해두는 영 제너레이션 메모리 영역으로 나뉨. 두 영역 모두 메모리가 가득차면 가비지 컬렉션에 의해 비워지고 이 기준은 즉 이 객체 사용되고 있는가기준으로 올드제너레이션과 영제너레이션에서 저장되고 사라짐.
힙 메모리는 자바 가상 머신이 시작될때 만들어진다. 이 메모리는 어플리케이션이 실행되는 동안 사용된다. 자바 런타임이 메모리를 오브젝츠와 자바런타임환경에게 할당하기 위해 이 힙 영역을 사용한다.
하나의 오브젝트(객체)가 만들어질 때, 그것은 반드시 힙 영역에서 만들어지며 전역 접근성을 가진다. 이말은 모든 객체는 어플리케이션의 어디에서나 참조될 수 있다는 말이다.
객체는 두 개념에 의해 관리된다. 가비지 컬렉션 그리고 영 제너레이션 , 올드 제너레이션
가비지 컬렉션은 메서드안에서 어떤 참조도 없는 객체들에의한 어떤것이든 제거해줌으로써 메모리를 비워주기위해 작동한다. 이것들은 더이상 사용되지 않는 객체들이다. 그러한 객체들을 제거하는것은 힙 영역에서 더 이상 어떠한 공간도 차지하지 않는 것을 보장해준다.
영 제너레이션과 올드 제너레이션은 힙 스페이스를 두 제너레이션으로 분류함으로써 가비지 컬렉션을 위한 오브젝트들을 우선순위에 놓는 것을 돕는다.
이러한 공간(nursery 라고 부름)은 새로운 오브젝트들이 저장되는 영 제너레이션이다. 이 공간이 가득 차면 가비지 컬렉션은 그것을 청소해버린다. 오직 그 메모리 공간이 가득 찼을때만이라는 것을 주목하라. 여전히 올드 제너레이션에는 메모리가 있다. 올드 제너레이션은 (영제너레이션에서) 충분히 오래 머물렀던 객체들의 집이다. 올드 제너레이션이 공간을 다 쓸 때, 가비지 컬렉터는 이전 공간에서 더 이상 사용되지 않는 오브젝트들을 제거한다. 다시, 오직 힙영역이 풀일 때, 올드 가비지 컬렉션이 일어난다. 여전히 널서리(nursery)에는 공간이 있다.
What is Java Heap Space
It is created by the Java Virtual Machine when it starts. The memory is used as long as the application is running. Java runtime uses it to allocate memory to objects and Java Runtime Environment (JRE) classes.
When an object is created, it is always created in Heap and has global access. That means all objects can be referenced from anywhere in the application.
It is managed by two concepts: Garbage collection and young-generation, old-generation.
Garbage collection works to free memory by clearing any by objects without any references in the methods. These are objects that are no longer being used. Clearing them ensures they don’t take up space in the Heap.
Young-generation, old-generation helps prioritize objects for garbage collection by dividing Java Heap Space into two generations.
The nursery is the younger generation where the new objects are stored. When the nursery is full, garbage collection cleans it out. Note only the memory space for the nursery is full. There is still memory in the old generation.
The old generation is home to objects have been around long enough. When the old generation runs out of room, garbage collection removes the objects not being used in the old space. Again, only part of the Heap is full when old garbage collection happens. There is still room in the nursery.
가비지 컬렉터(Garbage Colloertor)
주기적으로 JVM heap 메모리를 점검하면서 스택에서 참조되지 않는 객체를 메모리에서 해제하는 장치
스택 메모리(Stack Memory)
이것은 메소드가 일어날때 변수의 값들이 저장되는 임시 메모리이다. 메서드가 끝난 후에는 그러한 값들을 가지고 있는 메모리는 새로운 메서드를 위한 공간을 만들기 위해 청소된다.
새로운 메서드가 발생될때, 새로운 블럭의 메모리가 스택 영역에서 생성될 것 이다. 이러한 새로운 블럭은 메서드에 의해 불러와진 일시적인 값들을 저장하고 메서드에 의해 사용되고 있는 힙 영역에 저장된 오브젝트의 참조값을 저장할 것이다.
이 블럭에서의 모든 값들은 오직 현재 메서드에 의해서만 접근가능하며 일단 그것이 끝난뒤에는 존재하지 않을 것이다. 메서드가 끝나면 그 블럭은 지워진다. 불러와진 다음 메서드는 그러한 빈 블럭을 사용할 것이다. 이것은 즉'후입 선출' (마지막 들어온것이 먼저 나간다) 메서드는 필요한 값들을 찾는것을 용이하게 하고 그러한 값들에 더 빠른 접근을 가능하게한다.
What is Java Stack Memory?
This is the temporary memory where variable values are stored when their methods are invoked. After the method is finished, the memory containing those values is cleared to make room for new methods.
When a new method is invoked, a new block of memory will be created in the Stack. This new block will store the temporary values invoked by the method and references to objects stored in the Heap that are being used by the method.
Any values in this block are only accessible by the current method and will not exist once it ends.
When the method ends, that block will be erased. The next method invoked will use that empty block.
This “last in, first out” method makes it easy to find the values needed and allows fast access to those values.
다시 참조, 참조 변수
자바에서는 데이터 타입에 크게 두 가지 원시 타입(Primitive Type)과 참조타입(Reference Type)이 있다.
원시 타입은 쉽게 말해, 정수, 실수, 문자, 논리 리터럴등의 실제 데이터 값을 저장하는 타입이고,
참조 타입은 객체(Object)의 번지를 참조(주소를 저장)하는 타입으로 메모리 번지 값을 통해 객체를 참조하는 타입이다.
참조 타입(Reference Type)
참조 타입은 원시 타입을 제외한 타입들(문자열, 배열, 열거, 클래스, 인터페이스)을 말한다.
Java에서 실제 객체는 힙 영역에 저장되며 참조 타입 변수는 스택 영역에 실제 객체들의 주소를 저장하여, 객체를 사용할때 마다 참조 변수에 저장된 객체의 주소를 불러와 사용하는 방식이다.
- EXAMPLE
스택 영역힙 영역
int age = 18 char alphabetC = 'c' String typeOfCoffee = 10101번지 |
10101번지 : "아메리카노" |
- 정적 메모리 스택(Stack) 영역
스택 영역에는 기본타입 변수가 할당되고 변수의 실제 값들이 저장된다.
참조 타입의 변수들은 이 스택 영역에서 힙 영역에 생성된 객체들의 주소 값을 저장하고 있는다.
객체 안의 메소드의 작업이 종료되면 할당되었던 메모리 공간은 반환되어 비워진다.
- 동적 메모리 힙(Heap) 영역
힙 영역에는 객체와 배열이 생성된다.
그리고 참조타입(배열, 클래스, 인터페이스 등)들이 이 객체들의 주소를 스택 영역에 저장한다.
기본타입 변수들과는 다르게 크기가 정해져 있지 않다.
프로그램 실행시 메모리에 동적으로 할당된다.
참조하는 변수가 없으면 자바의 가비지 컬렉터가 제거한다.
가비지 컬렉터(Garbage collector) : 메모리의 힙 영역에 할당된 더 이상 사용되지 않는 객체를 제거 하는 역할
이렇게 객체를 제거하며 메모리가 관리된다.
Boxing, Unboxing
Boxing(박싱)은 원시 타입을 참조 타입으로 변환 시키는 것을 말하고, Unboxing(언박싱)은 참조 타입을 원시 타입으로 변환 시키는 것을 말한다.
자바 1.5 이전에는 일일히 변환 과정을 거쳐주어야 했지만, 자바 1.5부터 추가된 Auto Boxing / Unboxing 기능으로 아래의 예시와 같이 명시적으로 원시타입을 참조타입으로 감싸주지 않아도 자동으로 Boxing / Unboxing 해준다.
int i = 10;
Integer integer = i;
이러한 Auto Boxing / Unboxing 기능은 메모리 누수의 원인이 될 수도 있다.
참조 변수의 선언
Account account = new Account();
위와같이 참조타입을 new 로 선언해줄 수 있음.
원시타입은 new 가 아니라 그냥 바로 int i = 10; 으로 생성
즉, 참조타입 변수는 new 로 생성 원시타입 변수는 바로 생성
둘다 되는 String 이란 문자열의 참조변수는 뭔데?
String str = "java";
String str1 = new String("java");
위와 같이 String 타입은 두개가 다 됨 -> String pool 개념이 필요함
s1,s2 와 같이 리터럴로 객체를 생성하면 스트링 풀에 같은 값이 있는지를 확인하고 주소를 리턴하고 없다면 새로운 객체를 만든 후 스트링 풀에 할당한 뒤 그 주소값을 리턴한다. (즉 어찌됬든 스트링풀을 통해 주소값을 가져옴)
s3,s4 처럼 참조변수 선언을 통해 객체를 만들면 힙메모리 영역에 다른 주소로 객체를 생성한다.
String str0 = "Java";
String str1 = new String("Java");
String str2 = "Java";
String str3 = new String("Java");
System.out.println(str0.equals(str1));
System.out.println(System.identityHashCode(str0));
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str3));
System.out.println(str0==str1);
System.out.println(str0==str2);
리터럴로 생성한 스트링은 가리키는 주소가 같고 스트링풀에 같은 주소로 참조되어있다.
new 방식의 로 생성한 스트링은 두 값이 같지않지 않다. -> 동일과 동등의 개념이 나옴
> Task :app:HelloWorld.main()
true
2060468723
622488023
1933863327
false
true
즉 리터럴로 선언한 스트링은 같은 주소의 '동일'한 것이고 new 로 선언한 스트링은 '동등'한 값을 가지는 다른 객체이다. 따라서 가지는 주소값도 다르다.
String Pool과 Intern
String Pool은 HashMap 형태로 되어있으며 "~"와 같이 리터럴을 사용하여 String 객체를 생성하면 String Pool 내에서 기존의 같은 값을 가지는 객체가 있는지 검사 후 있다면 그 객체의 참조값을 return 하고, 아니라면 새로 String 객체 생성 후 그 참조값을 return 합니다. 이러한 과정을 intern이라고 합니다. 그리고 리터럴로 생성 시 intern()이라는 메서드를 수행함을 알 수 있습니다.
리터럴 방식으로 생성된 String 객체의 참조값은 모두 String Pool 주소값을 지정하고 있고 값을 찾는 방식은 String Pool로 찾아간 후 String Pool 내에서 intern의 과정을 거쳐서 찾는 값과 같은 값을 가진 부분의 주소값을 return 해주는 방식인거죠.
String Pool을 사용하는 이유는 JVM의 객체가 생성되는 공간인 Heap에 계속해서 객체를 생성하게 되면 메모리 공간적 측면에서 비효율적이기 때문입니다. 따라서 Pool을 사용한 Caching(캐싱)을 통해서 이를 해결하게 위함이죠.
위의 intern 과정 때문에 가끔씩 겪게 되는 String 비교 시 특이점이 생깁니다.
String a = "good";
String b = "good";
String c = new String("good");
System.out.println(a == b); //true
System.out.println(a.equals(b)); //true
System.out.println(a == c) //false
System.out.println(a.equals(c)); //true
위의 코드에서 a와 b는 String Pool 내부의 같은 참조값을 가지게 되고 c는 String Pool 외부 Heap 영역에 다른 참조값을 가지며 생성되겠죠. 그리고 두 가지 비교 방식의 차이에 따라 주소 값과 실제값을 비교하고 그러므로 3번째 예시같은 경우에는 false가 나오게 됩니다.
- == : 주소값 비교
- string.equals() : 실제값 비교
gradlew 명령어
gradle 과 gradlew 차이(이건 해석귀차느니 알아서들 보...길)
gradlew command
The gradlew command, also known as the Gradle wrapper, is a slightly different beast. It’s a script that comes packaged up within a project. Yes, it gets committed into version control so when you clone the project you get the gradlew script automatically.
1. No need to install gradle locally
The gradlew script doesn’t rely on a local Gradle installation. It goes and fetches a Gradle installation from the internet the first time it runs on your local machine, and caches it. This makes it super-easy for anybody anywhere to clone a project and build it.
2. Fixed version
The gradlew script is tied to a specific Gradle version. That’s very useful, because it means whoever manages the project can enforce what version of Gradle should be used to build it. Gradle features are not always compatible between versions, so using the Gradle wrapper means the project will get built consistently every time. Of course, this relies on the person building the project ways using the gradlew command.
gradle 명령어 의미
$ gradle run
Running applications
It is common for applications to be run with the run task, which assembles the application and executes some script or binary.
$ gradle build
Computing all outputs
It is common in Gradle builds for the build task to designate assembling all outputs and running all checks.
$ gradle test
You can also run a task for all subprojects by using a task selector that consists of the task name only. For example, this will run the "test" task for all subprojects when invoked from the root project directory:
$ gradle clean
Cleaning outputs
You can delete the contents of the build directory using the clean task, though doing so will cause pre-computed outputs to be lost, causing significant additional build time for the subsequent task execution.
$ gradle tasks
Listing tasks
Running gradle tasks gives you a list of the main tasks of the selected project. This report shows the default tasks for the project, if any, and a description for each task.
gradle compile
컴파일 하라는 뜻
'개발공부하며 느낀 인생 공부' 카테고리의 다른 글
[Intellij] 인텔리제이 No such file or directory 문제 해결 (0) | 2022.07.11 |
---|---|
동료가 내 점심을 가지고 til을 쓰라고 했다. 헤헿[220710 til] (0) | 2022.07.10 |
관심사의 분리와 객체지향 그리고 코딩이 어려운 이유(행하는 주체와 그것을 받아오는 대상의 정의의 어려움) [20220709 til] (0) | 2022.07.09 |
너무 가까이 보면 당연한 것도 보이지 않는다[20220708 til2] (0) | 2022.07.09 |
복습의 복습의 복습 이월된..주간회고[메가테라 9주차라 쓰고 이월 3주차 회고] (0) | 2022.07.08 |
댓글