728x90

https://www.acmicpc.net/problem/15686

생각의 흐름

1.최대 M개를 고르라는 말의 의미는 무엇이지?
=> 최대 M개를 안 고르는 경우도 있나?

2. 치킨집을 제거한다고 하는 경우, 다른 치킨집의 거리에 영향이 가는가?
=> 좌표로 계산하기 때문에 영향이 없음.

=> 1번은 모르겠으나, 2번의 특성을 본다면, 모든 경우의 수를 탐색해서 계산하면 그만이겠다는 생각이 들었다.
=> 조금 느릴 것 같은데, 빠르게 하는 방법은 없을까? => 그리디?
근데 N이 50이라 워낙 수가 작아서 총 칸이 250이고, 집은 커봐야 2N이라 100 밖에 안 된다는 생각에 모든 경우의 수를 구하려고 했다.

=> 마음에 걸리는 요소는 1번, M개 이건 뭐지?

조합.. 😑 👍

조합을 구현하고, 계산의 요소를 추가한 문제로 보인다.

조합은 어떻게 구한? 개수를 지정한 백트래킹이고, 해당 코드에 계산 요소만 가미하면 된다.

코드를 이쁘게 쓰려고 했지만, 변수명은 별로라.. 그래도 신경쓴 부분을 아래 적어본다.

enum State { EMPTY, HOUSE, CHICKEN }; =>  이넘을 이용해서 숫자를 0, 1, 2를 문자열로 나타내봄
int answer = INT_MAX; =>  climits 라이브러리 이용해서 사용해봄.

visited[r][c] = true; selected.push_back({ r, c }); 이런식으로 코드의 줄을 줄여보려고 노력해봄 🔥

#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
using namespace std;

// 2<=n<=50, 1 <= m <= 13
int n, m;
int board[50][50];
bool visited[50][50];
enum State { EMPTY, HOUSE, CHICKEN };

vector<pair<int, int>> chickens;
vector<pair<int, int>> houses;
vector<pair<int, int>> selected;
int answer = INT_MAX;

void calculate() {
    int distance = 0;
    for(int i=0; i<houses.size(); i++) {
        int minDistance = INT_MAX;
        for(int j=0; j<selected.size(); j++) {
            minDistance = min(minDistance, abs(houses[i].first - selected[j].first) + abs(houses[i].second - selected[j].second));
        }
        distance += minDistance;
    }
    answer = min(answer, distance);
}

void combination(int index, int count) {
    if(count == m) { calculate(); return; }
    
    for(int i=index; i<chickens.size(); i++) {
        int r = chickens[i].first; int c = chickens[i].second;
        if(visited[r][c]) {
            continue;
        }
        
        visited[r][c] = true; selected.push_back({ r, c });
        combination(i, count + 1);
        visited[r][c] = false; selected.pop_back(); 
    }
}

int main() {
    cin >> n >> m;
    
    for(int i=0; i<n; i++) for(int j=0; j<n; j++) {
        cin >> board[i][j];
        if(board[i][j] == HOUSE) houses.push_back({ i, j });
        if(board[i][j] == CHICKEN) chickens.push_back({ i, j });
    }
    
    combination(0, 0);
    cout << answer;
}
반응형
728x90

https://www.acmicpc.net/problem/14442
문제 설명보다는 키포인트를 짚어보겠다.

1. 벽을 부수고 이동한다는 의미

기본: 2차원 배열에서 상하좌우로 이동하며 최단 경로를 찾아간다.
응용: k번 만큼 막혀있는 길인 1을 뚫고 지나갈 수 있다.
=> K번 만큼 길을 뚫고 가는 상태를 visited 배열 상에 나타내야 한다.
어느 분의 말에 따른다면 뚫고 간 상태와 안 뚫고 간 상태를 나타내기 위해서는 차원이 늘어야 한다고 말을 한다.
말이 어렵긴 한데, 자연스럽게 생각해보면 좋을 것 같다.

2. Enum 사용

enum RoadType {
    ROAD,
    BLOCK
};
회사에 취직하기 전엔 코테에서 사용하지 않았던 문법인데 더 알아보기 쉽지 않나 싶어서 써보았다.

3.배열의 크기를 미리 선언 또는 Vector를 이용하여 동적 생성

int board[1001][1001] = { 0, };
bool visited[1001][1001][11] = { false, };
취향 차이라 생각이 들고, 동적 생성하면 오히려 index of range 때문에 더 고민많이 할 것 같아서 미리 생성했다.
두 가지 방법 모두 알고 있는 것이 좋다고 생각한다.

4.struct 사용

struct Info {
    int x;
    int y;
    int k;
    int len;
};
struct는 pair, tuple, class로 사용 가능하다. 2가지 값까지는 pair가 편하다. 다만 3가지 이후로는 tuple은 문법을 또 외워야 한다는 점이 별로다. 그리고 개인적으로 손이 안 익는다. class는 복잡하다. 물론 OOP가 맞지만 여긴 코테니까..그래서 struct 문법을 애용한다.실수를 덜 하게 되는 것다.
또한 큐는 내가 어떻게 이동하고 있는 지에 대한 상태가 저장되는데, 상태의 값을 visited에 옮겨서 struct의 변수의 수를 줄이는 방법도 예전에 사용 많이 했는데, 굳이 그렇게 복잡하게 생각하면 실수를 많이 하게 된다. 상태는 한 곳에 저장해두는 것이 정신 건강 상 좋다.

5.k 값 수정하기

int nk = cur.k + (board[nx][ny] == BLOCK ? 1 : 0);
next_k 값을 구할 때 board[nx][ny] 값을 확인해서 수정해준다. 삼항 연산자로 대체해서 코드의 길이를 줄여보았다.

// 벽 부수고 이동하기 2 https://www.acmicpc.net/problem/14442
// N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)
// (1, 1)과 (N, M)은 항상 0이라고 가정

// 첫째 줄에 최단 거리를 출력한다. 불가능할 때는 -1을 출력한다.
#include <iostream>
#include <cassert>
#include <vector>
#include <queue>
using namespace std;

enum RoadType {
    ROAD,
    BLOCK
};

struct Info {
    int x;
    int y;
    int k;
    int len;
};

int board[1001][1001] = { 0, };
bool visited[1001][1001][11] = { false, };

int dx[] = { -1, 1,  0, 0 };
int dy[] = { 0, 0, -1, 1 };

int main() {
    int n, m, k;
    cin >> n >> m >> k;

    // 1부터 넣었기 때문에 모든 인덱스는 0부터 시작한다.
    for (int i = 1; i <= n; i++) { 
        string temp;
        cin >> temp;
        for (int j = 1; j <= m; j++) { 
            board[i][j] = temp[j-1] == '0' ? 0 : 1;
        } 
    }

    queue<Info> q;

    q.push({ 1, 1, 0, 0 });
    visited[0][0][0] = true;

    while (!q.empty()) {
        Info cur = q.front(); q.pop();

        if (cur.x == n && cur.y == m) {
            cout << cur.len + 1;
            return 0;
        }

        for (int i = 0; i < 4; i++) {
            int nx = cur.x + dx[i];
            int ny = cur.y + dy[i];

            if (nx <= 0 || nx > n || ny <= 0 || ny > m) continue;

            int nk = cur.k + (board[nx][ny] == BLOCK ? 1 : 0);
            if (visited[nx][ny][nk] == true) continue;
            if (nk > k) continue;

            q.push({ nx, ny, nk, cur.len + 1 });
            visited[nx][ny][nk] = true;
        }
    }

    cout << -1;
}
반응형
728x90

객체지향 5 원칙이라해서 프로그램이 견고하며 고치기 쉬운 상태가 된다는 뭐.. 그런 거다.

그런데 이 원칙을 막상 실제 프레임워크를 이용하는, 예컨데 스프링 부트에서 적용하려고 한다면 막막하거나 그런 코드를 본 적이 없지 않은가?

나는 이런 느낌을  이벤트 관련 서비스 개발을 맡았을  때 느꼈다. 첫 번째는 기간 내 1회 참여였으나 이후 1일 1회 참여도 가능하냐는 요건이었다. 처음 코드와 테이블 설계 자체가 기간 내 1회 참여였기에 곤란하다는 느낌도 있었다. 하물며 2가지 요구사항이 시간을 두고 들어와서 기존 코드를 고치는 데 겁이 났었다.

하지만 이 문제는 간단하게 Api의 로직 내 If문 추가로 끝난다.

그 이후 요건이 또 들어왔다. 원래 이벤트 참가 시 참가 기록 및 쿠폰 발급이있다. 새로운 기능인 참가 기록만 하는 경우도 필요해졌다.

이런 식으로 하나의 서비스에 여러가지 목적이 담긴 코드가 섞이면서 의도가 불명확해지고 난잡해졌다.

그렇다면 의도가 명확해지고 코드가 간단해지는 방법은 없을까?

하지만 코드가 간단해지면서 한번에 되는 마법이란 없다. 모든 로직에 대한 코드는 어딘가에 있어야 한다는 사실을 잊지 말자 그렇기에 결국 Solid는 난잡한 방을 정리하는 정리법에 불과하다는 생각이 든다.

각 추상화 방식에는 방법과 목적이 있을 것이다. 각 의미를 생각해보자.

1. 인터페이스의 의미
스프링을 배우면 서비스는 인터페이스를 사용하라는 말을 하지만 인터페이스와 구현체가 1 대 1로 매핑되게 사용하는 경우가 흔하지 않나?

애초에 인터페이스는 무엇일까?

인터페이스를 설계서란 이야기를 많이 하지만 그게 옳은 표현일까?
설계서를 생각한다면 나는 레고 설계서가 생각이 나는데 꽤 두껍고 복잡했던 것으로 기억이 난다. 그래서인지 인터페이스를 만들 때에도 그런 두꺼운 레고 설계서를 만드는 경향이 있다는 것을 관찰했다.

코드에서 말하는 설계서는 객체에 대한 설계서, 즉 작은 부품에 대한 설계서를 일컫는 것이기에 다중 구현이 가능하도록 코드에서 지원해준다.

그렇다면 이벤트 서비스에는 어떤 기능이 들어가야 할까?

2. 추상 클래스와 추상 메소드
스프링 부트에서 추상 클래스를 써보았나? 그런 경험이 없다. 그리고 이게 가능한가? 보통 인터페이스만 사용했으니 더 그러하다. 추상 클래스는 무엇일까?

3. 상속과 구현
상속은 부모 클래스의 속성과 메소드를 자식 메소드가 사용할 수 있게 된다. 즉, 속성과 기능이 복제가 된다. 다른 언어에서는 다중 상속도 구현해주나 자바에서는 다중 상속을 지원하지 않는다.
구현은 인터페이스의 메소드 시그니처만 가지고 기능을 만들어야 한다.

4.추상 메소드와 디폴트 메소드
추상 클래스는 추상 메소드를 만들 수 있다. 인터페이스는 디폴트 메소드를 자바 8부터? 지원해주고 있다. 두 개의 차이는 무엇일까?

4. 스프링 빈과 공통 로직
빈으로 등록되는 객체는 싱글톤의 성격을 띄게 되는데, 빈을 의존성 주입을 받아서 사용하게 된다. 그러니까 인터페이스의 디폴트 메소드는 빈에 접근하려면 파라미터로 받을 수 밖에 없다.
반면 추상 클래스는 해당 빈을 변수로 가져갈 수 있다.

5. 동일한 인터페이스를 가지는 서비스가 많아지면 빈의 싱글톤 개념이 깨지게 된다. 그렇기 때문에 각 서비스에 빈 이름을 고유하게 설정해 줘야한다.

6. 웹 프로젝트의 경우 모든 입력은 Controller에서 온다. 그렇기 때문에 해당 서비스를 불러오는 방법을 어느 곳에 두냐에 따라서 코드가 더러워지는 곳을 정할 수 있다.

1. 필터 2. 컨트롤러 3. 서비스

코드를 적거나, 보기 좋게 적고 싶지만 그럴 시간이 없다.
시간이 날 때 막 적어둔 이 글을 풀어서 예시를 하나씩 적으면서 정리해보려고 한다.

이 글은 solid와 di, 난잡해지는 코드를 보며 생각했던 넋두리를  담은 글이다.

반응형
728x90

이전 글: https://koolreview.tistory.com/121

 

Spring DI 방법론

https://susuhan.notion.site/Spring-DI-6113d9eefba446c99413d1323abe9276 - 이쁘게 보기 - Spring DI 방법론 글의 목적 필드 의존성 주입과 setter 의존성 주입, 생성자 의존성 주입에 관한 차이를 알아가기 susuhan.notion.sit

koolreview.tistory.com

 예전에 DI에 대해 정리했었다. 그런데 회사 내에서 인터페이스를 사용하지 않고 있었다. 실제 Class만 이용해서 구현하고 있었다. 그런 이유는 하나의 인터페이스에 하나의 구현체만 존재하는 일종의 1대 1 구조로 되어 있는 경우가 많았기 때문이었다. 

 인터페이스를 쓰는 경우에도, 인터페이스가 없는 경우에도 의아스러움은 사라지지 않았다. 형식화되어 있는 것이 프레임워크이긴 하지만... 이게 맞을까? 진짜 DI가 무엇일까? 그냥 의존성을 주입한다는 건가? 그런 생각을 계속하게 되고 찝찝함은 남아있었다.

 인터페이스를 왜 쓸까? 설계서를 작성하는 것과 같은데, 구현체를 바꿔 쓰면서 유연성을 가지기 위함이 아닐까? 그런 유연성을 고민하다보면 if문으로 가능한 데 굳이? 인터페이스를 나눠서 써야하지? 이런 생각을 하게 된다.

다음과 같은 예를 생각해볼까?

 당신은 이벤트 신청 Api, 이벤트 참가 Api를 개발한다고 생각해보자. 그런데 이벤트란 여러 종류가 존재하지 않은가? 단순히 박스 이벤트, 룰렛 등 심지어 참가 방식도 기간 내 참가, 매일 참가 등 많다. 그런 모든 이벤트를 하나의 EventService로 만든다고 생각해보자.

 아마 당신은 Http Call 파라미터로 이벤트의 종류를 보내주지 않을까? 그리고 그 종류에 따라 함수를 따로 쓰고 있지 않을까? 사실 그래도 상관은 없을 것 같긴 한데... 함수가 복잡해지면.. 아니 처음엔 4개에 였던 파라미터가 5개로 늘어나고, 너무 다른 로직을 가지게 된다면 다른 이름의 함수를 만들거나 하지 않을까? 하나의 서비스에 너무 많은 범용성을 가지고 있는 것이 아닐까?

 구글, 페이스북, 카카오, 네이버 등 Oauth 로그인 개발에는 전략 패턴이 들어가서 각 프로바이더에 맞는 로직이 따로 각 Class마다 들어간다. 위 예시인 EventService도 그런 것이 아닐까?

 그런데 결국 본질은 Event이기 때문에 DB 적재 함수를 따로 만들어 동일하게 사용할 수도 있다. 그런 경우 모든 구현체에 다 구현해줘야 하나? 그런 경우 인터페이스 Default 메소드가 떠오르지 않을까? 그런데 이 Deafult 메소드에서는 Bean에 접근할 수가 없어서 불편한 경우가 발생한다.

이런 경우에는 어떻게 해야할까? 그리고 여러 구현체를 가지고 있는 경우 어떻게 구현체를 불러서 써야할까? 그리고 구현체는 여러 개지만 운영에서만 사용하는 구현체가 1개라면 어떻게 개발해야 할까?

아니 그래서 유연한가? 의존성 주입은 유연함이고 인터페이스는 SOLID의 D인 DIP 그런 의존관계 역전 법칙을 잘 사용하고 있는 것인가?

시간 날 때 다음 글에서 구체적인 예시를 하나씩 적어봐야겠다.

반응형
728x90

이전 글: 웹 최적화 캐시 Etag, Cache-Control

 

웹 최적화 캐시 Etag, Cache-Control

캐시 전략은 클라이언트와 서버에 각각 적용할 수 있다. 중요한 점은 서버에 I/O Call를 발생시키지 않아야 좋은 것이다. 서버에서 Redis나 Ehcache 활용하거나, 아니면 DB 수준에서 캐싱을 사용하든

koolreview.tistory.com

https://www.npmjs.com/package/sharp

 

sharp

High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images. Latest version: 0.33.5, last published: 12 days ago. Start using sharp in your project by running `npm i sharp`. There are 4673 other projec

www.npmjs.com

sharp 라이브러리에서 webp으로 변환해주는 간단한 코드가 있다.
설치: npm init -> npm install sharp

더 자세한 코드는 라이브러리 문서를 읽으면 해결할 수 있다.

import shartp from "sharp"

sharp('prevImage.jpg')
  .toFormat('webp')
  .toFile('webpImage.webp', (err, info) => {
    if (err) {
      console.error('Error:', err);
    } else {
      console.log('Success:', info);
    }
  });

jpg를 webp으로 변환해서 2개의 사진을 가지고 있으면 된다.

그 이후 HTML에서 webp을 img src에 넣어주면 된다.

    <img src="./webpImg/testImg.webp" alt="img">

 그리고 webp 이미지 조그만한 사진을 하나 따로 준비해두고, 아래 JS에서 처럼 이미지 객체를 만들고 미리 호출해서 로드가 되는지 확인한다. 그리고 동작을 하지 않는다면 replace를 이용해서 url를 변경해주면 된다.

추가적으로 확장자가 모든 이미지가 동일하지 않을 것이다. 그런 경우 img tag에 data로 넣어서 해당 이미지의 확장자를 넣어두고 지원하지 않는 라이브러리에서는 해당 확장자를 data에서 빼서 쓰면 된다.

document.addEventListener("DOMContentLoaded", function () {
    supportsWebP(function (supported) {
        if (!supported) {
            document.querySelectorAll('img').forEach(function (img) {
                var webpSrc = img.getAttribute('src');
                if (webpSrc && webpSrc.endsWith('.webp')) {
                    var jpgSrc = webpSrc.replace('.webp', '.jpg');
                    img.setAttribute('src', jpgSrc);
                }
            });
        }
    });
});

function supportsWebP(callback) {
    var webP = new Image();
    webP.src = "./webpImg/testImg.webp";
    webP.onload = webP.onerror = function () {
        callback(webP.height === 40);
    };
}
반응형
728x90

 캐시 전략은 클라이언트와 서버에 각각 적용할 수 있다. 중요한 점은 서버에 I/O Call를 발생시키지 않아야 좋은 것이다.

 서버에서 Redis나 Ehcache 활용하거나, 아니면 DB 수준에서 캐싱을 사용하든가 등등 서버단에서도 지원할 수 있는 방법은 많다. 하지만 중요한 건 사용자가 Call를 요청의 수가 적으면 서버단의 CPU를 쓰지 않을 수 있다. 그런 기법의 예로는 디바운싱도 있다. 디바운싱은 화면의 UI를 변경을 억제하는 데 쓰일 수도 있지만 Call을 여러 번 쏘지 않도록 유도할 수도 있다. 클라이언트 단, 아니 Http Cache에 대해 소개해보려고 한다.

우린 결국 Http Call를 무조건 요청한다. 이는 Html, css, Js 등 모든 리소스를 받을 때 모두 통용된다. 이런 Http 헤더에 Cache-Control key에 value를 넣어 value에 적혀있는 시간만큼 Client에 있는 값을 쓸 수 있도록 할 수 있다. Cache-Control에 적혀있는 시간이 지나면 기존과 동일하게 실제 Call이 요청된다.

이 Cache-Control과 독립적으로 사용할 수 있는 친구는 Etag다. Etag는 반환되는 리소스의 값을 해시로 준다. 그리고 해당 값을 서버로 Client가 자동으로 보내고, 또한 스프링의 경우에는 Filter를 이용하거나 직접 request header에서 Etag를 꺼내서 직접 비교해도 된다. Etag의 Hash 값은 어떻게 만들어질까? Md5Utils.java를 이용해서 만들어진다.

 

반응형
728x90

 IT 서적은 일반 책과 다르게 만원부터 비싸면 6만원까지 넘어가는 경우가 있다. 꽤나 비싸서 이걸 어떻게 다 사서 보기도 애매하고, 도서관에 빌려서 보기도 애매하다. 또 ebook을 빌려서 볼 수 있는 밀리의 서재나 리디북스도 거의 책이 없어서 보기가 어렵다. 학교 도서관에 꾸준히 요청해서 책을 늘려나갈 수도 있겠지만 오래 걸린다.

학교에서 오리얼리를 지원한다면 영문 서적을 공짜로 볼 수도 있다.

IT 서적 신간을 무료로 읽는 방법이 있다. 출판사에서 책을 출간하기 전 베타 리더를 모집하거나 출간 후 이벤트로 각 커뮤니티에서 랜덤으로 몇 명에게 책을 나눠주기도 한다. 또 랜덤 말고도 서평단을 모집하여 책을 주기도 한다.

 각 차이점이 있는데, 먼저 베타 리더는 자신의 소속과 이름을 책에 남겨둘 수 있다. 어느 이득이 있는지는 모르지만 그렇다. 또한 출간되는 서적 한권과 그 출판사에서 있는 서적을 하나 받을 수 있다. 또한 출간 전 미리 서적을 읽어볼 수 있다는 점에서 좋다.

서평단은 블로그나 온라인 서점에 리뷰를 남기는 형태로 진행된다. 서평하는 책을 한권 받을 수 있다는 점이 좋다.

랜덤은 그야말로 책 한권 받고 끝나기 때문에 리뷰나 꼭 책을 읽지 않아도 된다는 점이 있다.

그럼 어디서 이런 정보를 얻을 수 있을까?

먼저 자주 이용하는 커뮤니티에서 서평 관련 이벤트를 제공할 수 있다.
https://okky.kr/

 

OKKY - All That Developer

OKKY는 국내 최대 개발자 지식공유 플랫폼입니다. 개발자에게 필요한 기술 Q&A, 아티클, 커리어, 네트워킹, 취업, IT행사를 지원합니다

okky.kr

전에 Okky에서 서평관련 이벤트를 진행하는 것을 보았고 해당 사이트를 운영하시는 분께서 간혹 년에 한번 정도 유튜브에서 책 나눔 이벤트를 진행하신다.

보통 페이스북, 트위터에서 각 IT 출판서를 검색해서 팔로우를 진행하고, 페이스북에는 it관련 그룹을 찾아서 가입해두면 각 커뮤니티에서 글이 올라온다.

제이펍에서 이번에 14기 베타 리더단을 뽑아서 생각나는 김에 글을 작성해보았다.

반응형
728x90

매일 열심히 앱에 들어가서 적립금을 모으는 것은 아니지만, 대게 적립금 유효기간에 따라 최대 6천원까지 모은 적이 있다. 물론 종이 서적 구매 금액과 ebook 적립금이 섞이는 경우도 있지만 거의 6천원 모아서 살 수 있다. 아래는 지난 3개월 동안 모았던 적립금 내역이다.

보통 적립금은 신간 서적이 올라오는 경우 별점을 부여하여 적립금을 얻을 수 있다.
그리고 이벤트를 참여해서 얻고, 월 1회로 줄어든 앱 접속 금액도 얻을 수 있다.
매주 금요일은 ebook 적립금을 최대 3000원까지 주는 적립금 이벤트도 있어서 할만하다.

2024.7.27 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   4,500
2024.7.25 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   5,500
2024.7.25 이벤트발급(온라인전용) 7월 감사 적립금(온라인 1만원 이상 구매 시. 우주점, C2C, 전자책 제외) 1,000   4,500
2024.7.25 이벤트발급(온라인전용) 깜짝 퀴즈 적립금 1천원 (전자책 경제경영/자기계발 분야 1만원 이상 주문 시, 7/27까 1,000   3,500
2024.7.24 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,500
2024.7.23 이벤트발급(온라인전용) 편집장의 퀴즈 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책,중고,C2C,우주점 적 500   2,500
2024.7.23 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,000
2024.7.22 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   1,000
2024.7.21 이벤트발급(온라인전용) 7월 퀴즈 적립금 (온라인 전용) 1,000   4,000
2024.7.21 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,000
2024.7.20 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,000
2024.7.19 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,000
2024.7.19 이벤트발급(온라인전용) 7월 퀴즈 적립금 (온라인 전용) 1,000   1,000
2024.7.17 이벤트발급(온라인전용) 7월 퀴즈 적립금 (온라인 전용) 1,000   1,000
2024.7.12 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,000
2024.7.10 이벤트발급(온라인전용) 공부 지원 적립금 2천원 (국내도서 전용, 발급 당일 참고서 1만원 이상 구매 시 사용 가 2,000   4,000
2024.7.10 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,000
2024.7.10 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   1,000
2024.7.1 이벤트발급(온라인전용) 쇼핑앱 접속 적립금 (온라인 전용. C2C 주문 제외) 1,000   4,180
2024.7.1 이벤트발급 25주년 반반퀴즈 1천원 적립금 1,000   3,180
2024.7.1 이벤트발급(온라인전용) 7월 퀴즈 적립금 (온라인 전용) 1,000   2,180
2024.6.29 이벤트발급(온라인전용) 쇼핑앱 접속 적립금 (온라인 전용. C2C 주문 제외) 1,000   4,500
2024.6.29 이벤트발급(온라인전용) 편집장의 퀴즈 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책,중고,C2C,우주점 적 500   3,500
2024.6.29 이벤트발급(온라인전용) 7월 퀴즈 적립금 (온라인 전용) 1,000   3,000
2024.6.29 이벤트발급 25주년 반반퀴즈 1천원 적립금 1,000   2,000
2024.6.28 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   1,000
2024.6.24 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,000
2024.6.22 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,000
2024.6.20 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,000
2024.6.20 이벤트발급(온라인전용) 6월 감사 적립금(온라인 1만원 이상 구매 시. 우주점, C2C, 전자책 제외) 1,000   2,000
2024.6.19 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   1,000
2024.6.6 이벤트발급(온라인전용) 6월 퀴즈 적립금 (온라인 전용) 1,000   7,800
2024.6.6 이벤트발급(온라인전용) 쇼핑앱 접속 적립금 (온라인 전용. C2C 주문 제외) 1,000   6,800
2024.6.6 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   5,800
2024.6.5 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   4,800
2024.6.4 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   4,800
2024.6.3 이벤트발급 인생네권 공개 이벤트 1,000   5,300
2024.6.2 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   4,300
2024.6.1 이벤트발급(온라인전용) 쇼핑앱 접속 적립금 (온라인 전용. C2C 주문 제외) 1,000   5,300
2024.6.1 이벤트발급(온라인전용) 6월 퀴즈 적립금 (온라인 전용) 1,000   4,300
2024.6.1 이벤트발급(온라인전용) 편집장의 퀴즈 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책,중고,C2C,우주점 적 500   3,300
2024.6.1 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,800
2024.5.29 이벤트발급(온라인전용) 독서지원 적립금 1천원 (국내도서 전용, 발급 당일 온라인 1만원 이상 구매 시 사용 가능 1,000   5,300
2024.5.28 이벤트발급(온라인전용) 편집장의 퀴즈 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책,중고,C2C,우주점 적 500   5,300
2024.5.28 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   4,800
2024.5.27 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   4,800
2024.5.26 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,800
2024.5.25 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,800
2024.5.25 이벤트발급(온라인전용) 편집장의 퀴즈 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책,중고,C2C,우주점 적 500   2,800
2024.5.23 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,800
2024.5.21 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   5,800
2024.5.20 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   5,800
2024.5.20 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   4,800
2024.5.19 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,500
2024.5.18 이벤트발급(온라인전용) 편집장의 퀴즈 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책,중고,C2C,우주점 적 500   2,500
2024.5.18 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,000
2024.5.16 이벤트발급(온라인전용) 독서지원 적립금 1천원 (국내도서 전용, 발급 당일 온라인 1만원 이상 구매 시 사용 가능 1,000   8,440
2024.5.16 이벤트발급(온라인전용) 5월 퀴즈 적립금 (온라인 전용) 1,000   7,440
2024.5.16 이벤트발급(온라인전용) 쇼핑앱 접속 적립금 (온라인 전용. C2C 주문 제외) 1,000   6,440
2024.5.16 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   5,440
2024.5.14 이벤트발급(온라인전용) 석탄일 독서 지원 적립금 (전자책 2만원 이상 주문시, ~5/16 까지 사용) 2,000   4,440
2024.5.11 이벤트발급(온라인전용) 편집장의 퀴즈 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책,중고,C2C,우주점 적 500   3,440
2024.5.11 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   2,940
2024.5.9 이벤트발급(온라인전용) 5월 이달의 책 투표 적립금 (발급 당일 사용, 국내도서 1만원 이상 구매 시 적용) 200   4,140
2024.5.8 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   3,940
2024.5.7 이벤트발급(온라인전용) 4월 이달의 책 투표 적립금 (발급 당일 사용, 국내도서 1만원 이상 구매 시 적용) 200   2,200
2024.5.7 이벤트발급(온라인전용) 쇼핑앱 접속 적립금 (온라인 전용. C2C 주문 제외) 1,000   2,000
2024.5.7 이벤트발급(온라인전용) 쇼핑앱 푸시 광고 적립금(온라인 국내도서 1만원 이상 구매 시, 전자책, 업체직배송, 우주 1,000   1,000
2024.4.29 이벤트발급(온라인전용) 5월 퀴즈 적립금 (온라인 전용) 1,000   6,000
2024.4.29 이벤트발급(온라인전용) 깜짝 퀴즈 적립금 1천원 (전자책 경제경영/자기계발 분야 1만원 이상 주문 시, 5/1까지 1,000   5,000
반응형

+ Recent posts