저희 팀에서 구상하고 있는 프로젝트의 핵심 기능은 콜라보 리퀘스트 요청입니다.

 

1. 기존의 게시물에 콜라보를 하고 싶으면 콜라보 리퀘스트를 보냅니다.

2. 콜라보 리퀘스트를 받은 게시물의 작성자가 승인을 하면

3. 게시글 조회시 승인된 콜라보 리퀘스트의 목록이 함께 조회가 됩니다.

 

제가 맡은 도메인이 바로 이 콜라보리퀘스트입니다. 깃헙의 pull request에서 영감을 받은 기능입니다.

현재 CRUD의 CR만 구현된 상태입니다. 승인을 위해 보여지는 상세 페이지와 승인이 완료된 콜라보리스트를 보여주는 기능을 각각 구현했습니다.

 

수정 기능과 삭제 기능은 오늘 만들어 놓으려고 합니다.

승인되기 전에만 수정 또는 삭제 할 수 있게 합니다.

 

 

위의 기능들은 CRUD이기 때문에 기존에 했던 프로젝트와 크게 다르지는 않습니다.

그래서 제가 욕심을 내고 있는 기능은 알람기능입니다.

 

원하는 기능은 아래와 같습니다.

 

1. 콜라보 리퀘스트를 작성하면, 해당 게시글의 작성자에게 승인 요청 알람 보내기

2. 승인이 완료되면, 해당 콜라보 리퀘스트 작성자에게 승인 완료 알람 보내기

 

CRUD가 끝나면 깊이 파볼 생각입니다.

 

List 수정 하는 법

삭제하는 법은 querydsl을 사용해서 처리했는데 수정은 모르겠어서 일단은 삭제 후 새로 저장하는 방법으로 구현했습니다.

 

수정 시, musicList의 music의 갯수가 늘어나거나 줄어드는 경우가 있어서 뭔가 복잡한 느낌이 듭니다. 

 

결국 알아낸 방법은 똑같이 query를 수정해주면 된다는 것이다.

삭제할 때는 다음과 같은 코드를 사용해서 musicList를 삭제해주었다. Music은 CollaboRequest를 외래키로 가지고 있다.

 

@Transactional
@Modifying
@Query("DELETE from Music c where c.collaboRequest = :collaboRequest")
void deleteAllByCollaboRequest(@Param("collaboRequest") CollaboRequest collaboRequestId);

 

QueryDSL

  1. 문자가 아닌 코드로 쿼리를 작성함으로써, 컴파일 시점에 문법 오류를 쉽게 확인할 수 있다.
  2. 자동 완성 등 IDE의 도움을 받을 수 있다.
  3. 동적인 쿼리 작성이 편리하다.
  4. 쿼리 작성 시 제약 조건 등을 메서드 추출을 통해 재사용할 수 있다.

 

QueryDSL이란 것으로 쿼리를 더 쉽게 커스텀해서 사용할 수 있다.

이제 알았으니 Update를 위한 query를 만들어보자.

https://stackoverflow.com/questions/31937540/update-list-of-entities-in-one-query-jpa

 

Update List of entities in one query jpa

I need to update a list of objects in one query. I have class Parent which has a list of Child in ManyToMany relation. I need to update a list of Parent by setting children list to empty(remove all

stackoverflow.com

개발자의 친구 stackOverFlow를 참조해서 키워드를 찾았다.

 

아래와 같이 하면 된다고 한다.

UPDATE [테이블] SET [] = '변경할값' WHERE [조건]

 

좀 더 고민해봐야겠다...

어제 거의 2시간만에 콜라보리퀘스트 승인 기능을 만들고, 승인한 게시글만 불러오는 기능을 만들었습니다. 

처음 부트캠프를 시작했을 때에 비하면 장족의 발전입니다. 이제는 스스로 생각해서 코딩하는 경우가 더 많아졌습니다. 물론 아직까지는 다른 사람의 코드를 보고 배우는 점이 더 많긴 합니다.

 

다른분들이 아침8시부터 같이 공부한다고 하니까 저도 내일부터는 8시에 출근 하려고요.

 

 

이제 코딩배운지 4개월차인 개발자 지망생입니다.

 

오늘 실전프로젝트 첫 멘토링이 있었습니다.

일주일간의 회고와 프로젝트에 대한 질문답변과 조언을 들었습니다.

SOLID 원칙

SOLID 원칙

클린 코드에 대한 이야기가 나왔는데 멘토님이 SOLID 원칙을 말씀해주셔서 찾아보았습니다.

로버트 C. 마틴이 2000년에 쓴 논문 Design Principles and Design Patterns에서 software rot에 대해 설명하면서 처음 소개된 개념입니다. 

S Single responsibility principle (단일책임원칙) - 하나의 클래스는 하나의 책임만 가진다.
O Open-closed principle (개방-폐쇄원칙) - 소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀있어야 한다.
L Liskov substitution principle (리스코프 치환 원칙) - 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
I Interface segregation principle (인터페이스 분리 원칙) - 특정 클라이언트를 위한 인터페이스 여러 개가 인터페이스 하나보다 낫다.
D Dependency Inversion principle (의존관계 역전 원칙) - 프로그래머는 "추상화에 의존하며, 구체화에 의존하면 안된다."

 

2004년에는 Michale Feathers에 의해 SOLID 라는 약어로 소개되었습니다.

 

SOLID 원칙들은 어떠한 객체지향 디자인에도 적용할 수 있습니다.

애자일 개발 또는 Adaptive software development(ASD)의 방식의 핵심 철학이 될 수 있습니다.

 

 

 

출처:

 

SOLID - Wikipedia

Object-oriented software engineering design principles This article is about the SOLID principles of object-oriented programming. For the fundamental state of matter, see Solid. For other uses, see Solid (disambiguation). In software engineering, SOLID is

en.wikipedia.org

 

 

실전주차 1주차에 대한 회고

솔직히 이번주차는 개인적으로 중요한 큰 이슈가 있어서 부트캠프에 100% 집중하지는 못했습니다.

하지만 맡은 역할은 다 구현을 했고 지금은 관련해서 refactoring을 하고 있습니다.

mapstruct도 처음 써봤고 직접 swagger를 적용하는 것도 처음입니다.

다른 분들의 저와는 달리 깔끔해보이는 코드를 보면서 반성도 하고 제 꺼에 적용도 해보면서 발전해나가고 있습니다.

 

생각보다 API 명세서를 수정해야하는 부분이 많이 보여서 처음에 설계한 대로 구현하긴 했지만 refactoring 해야할 부분들이 많이 보입니다.

저희 프로젝트는 백엔드 보다는 프론트엔드 부분의 역량이 중요해서 백엔드에 대해서 어떤 도전적인 모습을 보여줄 수 있을까 고민도 했는데 굳이 고민안해도 될 것 같습니다. 생각보다 구현이 어려운 부분이 많습니다. 

 

그래도 부트캠프 처음 들어왔을 때와 지금을 비교하면 천지차이라고 할 수 있습니다.

간단한 CRUD는 그냥 합니다.

 

이번주차에서 어려웠던 것은 한 request안에 여러 Entity들에 들어가는 값들을 받아와서 따로 그 Entity에 맞는 repository에 저장을 해주는 것이었습니다. 반대로는 (다른 Repository에 있는 정보를 하나의 Response Dto에 넣어서 보내주기)는 했는데 반대를 어떻게 해야할 지에 대한 고민이 있었습니다.

 

결론은 한 requestDto에 여러 entity의 값들을 받아와서 controller에서 두개의 dto로 나눠 service에 전달을 하는 거였습니다. 

 

코드 공유를 살짝 하자면 아래와 같습니다. MapStruct는 사랑입니다.

 

  @PostMapping("/api/post/{postid}/collabo")
    public ResponseEntity<?> collaboRequest(@PathVariable Long postid, @RequestBody RequestCollaboRequestDto requestCollaboRequestDto, @ApiIgnore @AuthenticationPrincipal CustomUserDetails customUserDetails){
        collaboRequestService.collaboRequest(postid, requestCollaboRequestDto.tocollaboRequestDetailsDto(), requestCollaboRequestDto.tosaveMusicDto(), customUserDetails.getMember());

        return SuccessResponse.toResponseEntity(COLLABO_REQUEST, null);

 

tocollaboRequestDetailsDto() 와 toSaveMusicDto()로 RequestCollaboRequestDto로 받아온 값들을 나눠서 service에 전달해주었습니다.

 

 

지금은 처음에 Musicfile를 하나만 작성할 수 있었는데 API 명세를 보니 조회할때는 musicList로 받아와서 여러개를 requestDto에 담을 수 있도록 수정하고 있습니다. 오늘 이거는 해놓고 퇴근하려고 합니다. 

 

 

 

 

실전프로젝트를 진행하면서 팀원들과 github을 활용하고 있다.

이슈를 만들고 로컬에서 작업하고 푸시하고 PR한다.

Pull Request를 함으로써

서로의 코드 리뷰까지 함께 진행하게 되는데 팀원들의 깔끔한 코드를 보면서 반성하게 된다.

뭔가 클린 코딩에 대해서는 나중에 생각하고 기능부터 구현하자가 되버려서 그런거 같다.

내가 구현 속도가 가장 느리기도 하다.

굳이 변명을 하자면 전공자와 국비 수료자 사이에 있다.

나는 이 부트캠프가 코딩 배우는건 아예 처음이고.

 

여튼 변명은 여기까지고,

다른 분들의 코드를 보면 자극이 된다.

어떻게 이렇게 이쁘게 잘짰지? 하는.

 

머리를 쓰고 그다음에 타이핑을 해야겠다.

타이핑하면서 머리를 쓰니

주먹구구식이 되는 듯하다.

 

전에 다른 팀원분이 주신 객체지향 생활체조를 다시한번 정독해야겠다.

 

1. 한 메서드에 오직 한 단계의 들여쓰기만 한다.
2. else 키워드를 쓰지 않는다
3. 모든 원시값과 문자열을 wrap 한다.
4. 한 줄에 점을 하나만 찍는다.
5. 줄여쓰지 않는다.
6. 모든 entity를 작게 유지한다.
7. 2개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
8. 일급 컬렉션을 쓴다
9. getter/setter/property를 쓰지 않는다

for문을 안돌리고 하는 방법을 알고 싶다.

이제 MapStruct는 유연하게 쓸수 있다.

MapStruct의 deepclone 기능이 왜 생겼는지 아시는지?

 

git hub 가니까 대화가 있었는데 개발자 문화가 너무 좋더라.

전 업계를 생각하면 한숨만 나온다.

 

https://github.com/mapstruct/mapstruct/issues/695

 

Including both shadow copy and deep copy may be better · Issue #695 · mapstruct/mapstruct

Sometimes,developer need shadow copy and somtimes deep copy may be a good choice . If mapstruct support both of them, and developer can configure it ,i think it's better. I don't know wheth...

github.com

 

2015년에 누군가 이슈를 제기한 것이 3년만에 현실이 되었다.

 

 

계속해서 Mapper와 Mapstruct를 사용해야하는데 전혀 이해가 안되있다.

의존성을 낮추기위해 dto보다 Mapper를 쓰고 Mapper는 mapstruct를 쓰면 더 쉽게 사용할 수 있다고한다.

 

Mapstruct를 숨쉬듯 사용할 수 있게 연습해보자.

 

MapStruct란?

type-safe bean mapping 클래스를 제공합니다.

Mapping의 내용을 일일히 적지 않아도 되어 개발 생산성이 높아지는 효과가 있습니다.

 

MapStruct 사용법

현재 진행하고 있는 최종 프로젝트(아마 Erd가 변경될 예정인)에서 제가 맡음 부분을 예시로 들겠습니다.

 

우선, Entity가 있어야 겠습니다. 

@Getter
@Entity
@NoArgsConstructor
public class CollaboRequest extends Timestamped {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String contents;

    @Column(nullable = false)
    private String nickname;

    @Column(columnDefinition = "boolean default true")
    private Boolean activated;

    @Column(columnDefinition = "boolean default false")
    private Boolean approval;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "POST_ID")
    private Post post;

 

 

그다음엔 Mapper를 만들어봅시다.

 

 

@Mapper
public interface CollaboRequestMapStruct {
    CollaboRequestMapStruct COLLABOREQUEST_MAPPER = Mappers.getMapper(CollaboRequestMapStruct.class);
    CollaboRequest RequestCollaboRequestDtotoCollaboRequest (RequestCollaboRequestDto requestCollaboRequestDt);

}

@Mapper 어노테이션을 클래스명 위에 넣어줍니다.

 

여기서 Dto명은 RequestCollaboRequest입니다.

네이밍을 엄청 헷갈리게 하고 있는 것 같습니다만 지금은 어쩔수 없습니다. 

제가 만들고 있는 Entity 명이 CollaboRequest이기 때문입니다...

CollaboRequest의 RequestDto입니다.

CollaboRequestRequest보다는 덜 헷갈립니다.

 

 

아래는 RequestDto 입니다. 

@Builder를 사용해줬습니다.

 

public class RequestCollaboRequestDto {

    public String title;
    public String contents;


    public CollaboRequestDto tocollaboRequestDto(){
        return CollaboRequestDto.builder()
                .title(title)
                .contents(contents)
                .build();
    }
}

 

콜라보 요청하는 사람으로부터 제목과 내용을 받아옵니다.

사실 음악 파일과 음악 종류(? 악기 등)을 받아와야하는데

Music Entity를 따로 설계를 해버려서 방법을 찾는 중입니다.(양방향 설계를 하면 되려나?)

 

@Service에서 Mapper를 사용해서 Entity로 변환해서 저장을 해줍니다.

 

나머지는 내일 계속.......

에러

Inferred type 'S' for type parameter 'S' is not within its bound; should extend

Inferred type 'S' for type parameter 'S' is not within its bound; should extend

에러가 생긴 곳은 repository.save를 쓰던 Service 에서 였습니다.

에러 원인

어제 지성으로 코딩하게 되었다고 좋아했는데 바보같은 실수를 하고 말았습니다.

repository를 작성할 때 extends JpaRepository를 하는데

변수의 순서를 바꿔서 적으니 오류가 났던 겁니다.

 

에러 해결

알맞은 위치로 변경해주니 에러가 사라졌습니다.

 

지성으로 코딩합시다.

 

 

 

 

 

이때까지 노션으로 api 명세서를 작성하다가 포스트맨으로 작성하니까 공유하기도 쉽고 작성하기도 쉽습니다.

팀원들과 하루종일 api 명세서를 작성하고 저녁 9시가 다되서야 드디어 코딩을 하기 시작했습니다.

여전히 정해지지 않은 부분이 있어서 일단은 우선적으로 필요한 기능만 개발을 진행하기로 했습니다.

Postman api 명세서

api와 erdcloud로 작성한 erd를 보면서 개발을 하는데 바로 쓱쓱 코드를 작성하는 저를 보면서 많이 발전했구나 느꼈습니다.

전에는 따라쓰는데 급급했다면 이제는 제가 주체적으로 뭐가 필요한지 생각해서 코드를 작성하고 있습니다.

 

이래서 취직할 수 있겠어라고 저 자신을 의심하고 부트캠프 프로그램을 의심했었는데 나도 모르는 새 발전한 모습을 보니까 나도 모를 자신감이 +1 상승했습니다. 

 

아직은 미미하지만 남은 1달 반 정도의 시간동안 +10을 만들어 보도록 하겠습니다.

 

😎😎😎😎

한 살 더 먹었지만 변한 건 없습니다.

 

늘어나는 것은 뱃살뿐.

 

드디어 디자이너님과의 회의를 통해 대략적인 와이어프레임을 정했습니다.

장장 2시간 동안의 회의 끝에 주요 기능은 콜라보레이션 쪽으로 가져가기로 했습니다.

 

백엔드 쪽은 CRUD 를 구현하는 것이 메인입니다.

생각보다 ERD는 복잡하지 않게 나와서 좋습니다.

 

 

저작권 관련해서 검증할 수 있는 방법이 있나 찾아보는데 아직까지는 못찾았습니다.

해가 바뀌었습니다.

 

날짜는 그저 사람들이 정해놓은 규칙일뿐이고 하루가 바뀌어 해가 변한다고 내가 변하지는 않지만,

그래도 새로 시작하는 마음이 들고 의욕이 넘치게 되는 것은 어쩔수가 없습니다.

이번달이 가기전에 Spring 관련해서 구매하논 강의를 다 듣겠습니다.

3주동안하는 실전프로젝트도 미친듯이 멋진 프로젝트를 만들어서 코딩인생(약 4개월...) 최고의 업적이 되도록 하겠습니다.

 

저의 코딩인생은 아직까지는 발전만 있을 뿐 ...

 

1월1일에 판교에서 새해맞이를 하며 software developer의 꿈을 키워봤습니다.

판교에서 새해맞이

 

+ Recent posts