Skip to content

[FE/BE] 공통 규칙 #112

@kkn1125

Description

@kkn1125

FE/BE 코드 규칙 설정

공통 사항

  1. 모델 객체 필드 값은 디폴트 값 없이 사용하는 것을 원칙으로 한다. (데이터 value를 의도적으로 제한하기 위함)
  2. 디폴트를 제거하는 다른 이유 : 부득이 null값이 들어가야할 때가 있다. 그럴 때 null값을 다른 값으로 디폴트 처리하면 코드 작업이 더 딜레이 될 것으로 생각하여 판단 함.

FE 공통 규칙

프론트에 생성하는 객체는 데이터를 주고 받는 그릇으로 활용하기 위해 생성. 공통으로 사용하는 함수를 개발해야 api개발에 사용할 때 편의성을 증대 시킬 수 있다. 유지보수성을 높히기 위한 이유도 포함.

Model

  • 소문자 camelCase로 변수명을 작성한다.
  • private으로 외부에서 접근 못하도록 설정한다.
  • PModel의 함수에 따르고 IModel에서 상속 받는 추상 함수는 재정의 할 때 타입을 준수한 범위 내에서 모든 코드 구조는 변경 가능하다.
  • 디렉토리는 src/apis/해당클래스명/index.ts 로 작성한다. type 설정이 많아지면 index.ts와 같은 위치에 types.ts를 생성하여 모듈화한다.
  • export는 default가 아닌 객체로 내보내는 것을 기본으로 한다.
  • 디렉토리에서 기능별로 나누려면 src/apis/기능명/index.ts 로 작성한다.
  • 공통의 api는 src/utils/index.ts 에 작성한다. 공통의 type은 src/apis/commonTypes.ts에 정의한다.

IModel의 개념

interface Model을 의미한다.

interface로서 모든 클래스에 필요한 공통의 함수명과 인자, 반환 값을 지정한다.

PModel의 개념

extends 하여 사용하기 위한 클래스로 공통으로 타입에 관계없이 사용할 수 있도록 확장하여 활용하기 위한 목적으로 만들어졌다.

// IModel과 PModel을 상속한 예시 코드
class User extends PModel implements IModel {
  private nickName: ModelStringValue;
  //...

  public set(column: UserColumn, value: ModelValue) {
    // ...
  }
}

API

api는 아래 규칙을 따른다.

  1. api 작업 시 [BE] 백엔드 계획 의논 #41 의 내용을 토대로 생성하며, 수정 사항 발생 시 정리하여 [BE] 백엔드 계획 의논 #41 에 추가로 코멘트를 생성한다.
  2. 수정사항은 백엔드 restController와 충분히 테스트 및 검토 후 반영한다.
  3. 함수 명칭은 MongoRepository 기준으로 하며 예시는 다음과 같다.
const findUserAll () { /* ... */ }
const findUserById (id: string) { /* ... */ }
const findDiaryByUid (uid: string) { /* ... */ }
const insertUser (user: User) { /* ... */ }
const updateUser (user: User) {
  const formData = user.makeFormData();
  return axios.put('/api/user', formData)
    .then(handleReceiveData)
    .catch(handleReceiveError);
}
const deleteUserById (id: string) { /* ... */ }

BE 공통 규칙

Entity 클래스

  • 소문자 camelCase로 변수명을 작성한다.
  • private으로 외부에서 접근 못하도록 설정한다.
  • update가 필요한 클래스에 한해서 Entity 클래스를 확장해서 replaceIfNotNull을 사용한다.
  • 객체 update에 필요한 함수 replaceIfNotNull 내용은 아래와 같다.
    public class Entity<T> {
        public T replaceIfNotNull(T compare) {
            List<Field> fields = Arrays.asList(this.getClass().getDeclaredFields());
            fields.forEach(field -> {
                try {
                    field.setAccessible(true);
                    Object compareField = field.get(compare);
                    Object thisField = field.get(this);
                    if (field.getName() == "userAuth") {
                        field.set(this, "USER");
                    } else {
                        field.set(this, compareField != null ? compareField : thisField);
                    }
                } catch (IllegalAccessException e) {
                    System.out.println("The value is null [" + field.getName() + "]");
                }
            });
            return (T) this;
        }
    }
    
    // 사용 예시
    public class User extends Entity<User> implements UserDetails {
      // ...
    }

Repository

  • 리파지토리 명칭은 ClassNameRepository로 한다.

  • config디렉토리 MongoAuditConfig에 지정해두었기 때문에 @repository는 달지 않는다.

  • ClassNameRepository : interface

  • ClassNameRepositoryCustom : interface - 커스터마이징 구현 함수 설정

  • ClassNameRepositoryCustomImpl : class - 커스터마이징 구현 함수 작성 (MongoTemplate를 생성자 주입으로 사용하는 것을 원칙으로 한다.)

기본적으로 단순한 findAll, findById, insert, deleteById는 ClassNameRepository에서 사용하고, 쿼리문이 필요한 함수만 커스터마이징하여 사용한다.

Service

  • restController를 무겁게 하는 것을 피하기 위해 Service는 필수로 사용한다.
  • Service에서 해당하는 Repository를 생성자 주입으로 사용하는 것을 원칙으로 한다.

함수 명칭은 ClassNameRepositoryCustomImpl, ClassNameService, ClassNameRestController 모두 동일하게 처리한다. 예를 들면 다음과 같다.

// DiaryRepositoryCustomImpl
class DiaryRepositoryCustomImpl implements DiaryRepositoryCustom {
  private MongoTemplate diaryTemplate;
  
  @Autowired
  DiaryRepositoryCustomImpl(MongoTemplate diaryTemplate) {
    this.diaryTemplate = diaryTemplate;
  }
  
  public Optional<User> findByUid (String uid) {
    Criteria cr = new Criteria("uid").is(uid);
    Query q = new Query(cr);
    return diaryTemplate.findOne(q, Diary.class);
  }
}

// DiaryService
@Service
class DiaryService {
  private DiaryRepository diaryRepository;
  
  @Autowired
  DiaryRepositoryCustomImpl(DiaryRepository diaryRepository) {
    this.diaryRepository= diaryRepository;
  }
  
  public User findByUid (String uid) {
    return diaryRepository.findByUid(uid).orElseThrow();
  }
}

// DiaryRestController
@RestController
@RequestMapping("/api")
class DiaryRestController {
  private DiaryService diaryService;
  
  @Autowired
  DiaryRepositoryCustomImpl(DiaryService diaryService) {
    this.diaryService= diaryService;
  }

  private String mapper(Object object) throws JsonProcessingException {
    return new ObjectMapper().writeValueAsString(object);
  }
  
  @GetMapping("/user/uid/{uid}")
  public String findByUid (@PathVariable("uid") String uid) throws JsonProcessingException {
    return mapper(diaryService.findByUid(uid));
  }
}

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions