카테고리 없음

[피로그래밍] 23기 활동후기 (2025.06.26~2025.08.19)

cygnusa 2025. 8. 18. 10:32

💡피로그래밍이란? 

피로그래밍은 전공자, 비전공자, 복수전공자 모두 지원할 수 있는 웹 프로그래밍 동아리이다.

23기의 유일한 막내가 되고 느낀점이 정말 많았는데, 이번기회에 차근차근 회고해보면 좋을 것 같다는 생각이 들었다.

💡1차 서류 + 코딩 테스트 (~06.06)

06.06 까지 서류&코테 제출, 합격 여부는 06.18에 나왔다.

태어나서 처음 겪어본 코테인데 낯선 문법도 있고, 시험기간이라는 제약 안에서 해결하려니까 어려움이 참 많았다.

아래는 1차 합격 화면인데, 정말 떨리고 감동적인 순간이였다.

피로23_1차합격!

 

💡2차 면접(06.14)

1차 합격 발표를 본 후,
간절한 마음을 담아 피로 면접 관련 티스토리를 모두 정독했다.

면접대비 공통질문,기술질문 스크립트를 만들어 암기했고,
전 기수분들 플젝도 꼼꼼히 숙지하고 갔는데 덕분에 면접때 좋은 인상을 받은 것 같다.😆

첫번째 면접자라 긴장을 많이 하고 갔는데, 면접해주시는 분들이 아이스브레이킹 해주시고, 너무 친절하셔서 긴장이 풀렸다.

위 사진은 최종합격의 순간을 담은 감동적인 스샷인데, 올해 들어 가장 행복한 순간이었던 것 같다.

 

💡정규세션

꿈에 그리던 동아리에 들어와 첫 세션을 들었는데,,, 상상과는 다른 벽을 느껴버렸다.

그렇지만 정규 세션 기간 중 한 주에 한 번씩 팀플을 하며 언니, 오빠들한테 배우고, 도움 받아면서

조금씩 적응했던 것 같다. 
세션 기간 중 보증금이...정말 많이 깎였지만, 지나놓고 보면 열정을 우주 끝까지 이끌어준 좋은 제도인 것 같다.

(보증금 절대 지켜..)

세션기간 팀플(1-2주차)
세션기간 팀플 (3-4주차)

세션기간때 했던 팀플에서 배웠던 것도 많았고, 팀원들과 짧지만 좋은 추억이 많았던 것 같다.

⭐️피로의 하이라이트,  3주간의 협업 프로젝트

끝나지 않을 것 같았던 정규세션 기간을 가뿐히 넘기고, 드디어 협업 프로젝트가 시작되었다.
프로젝트에 관해선 하고 싶은 이야기가 정말 많지만 작업 정리부터 하겠다.

🍀1주차

1주차에는 플로우차트를 바탕으로 피그마 페이지를 구현했다.

30페이지가 넘어가는 분량이었기에,, 창작의 고통을 제대로 느낄 수 있었다.
그리고 피그마를 아예 처음 다뤄봐서 그룹화, 토글 기능, 애니메이션, 프로토타입 등등 낯선 기능과 친해지는 데 시간이 걸렸던 것 같다.

창작의 고통을 선물해준 피그마

🍀2주차

2주차에 본격적인 8월을 맞이하며, 우리 FE들은 html 작업에 착수하기 시작했다.
BE에서 앱별로 view를 만들어주면 해당 앱의 기능들과 화면을 피그마에서 만들었던 것처럼 구현하면 됐다.

식사 기록 페이지 기본 구조 구현을 시작으로, 로그인 페이지, 메인페이지 등등 든든한 BE와 속도를 맞춰 같이 페이지들을 도장깨듯 구현해나갔다.

비오는날 작업하기

🍀3주차

개인적으로 1주,2주때도 체력저하로 인한 피로도가 쌓여있었다고 생각했으나,
그 모든 것들을 3주차가 능가해 버렸다. 

우리팀에서 예상치 못한 BIG issue 가 생길줄은 상상도 못했지만 모종의 사건이 발생했다.
그것을 수습하기 위해 BE가 끝없는 디버깅 작업과 싸우는 동안,
FE는 base.html 을 상속받고, 그동안 html 에 있었던 js요소를 모두 별도의 js폴더에 넣는 대규모 리팩토링 작업을 했다.
그리고 최종발표회를 하루 남기고, 낮도 밤도 아닌 기이해진 수면패턴과 함께 우리의 플젝을 완성시킬 수 있었다.

 

드디어 탄생한 우리의 헬스턴트!

 

💡기술스택 &  핵심 기능 구현

기술 스택

  • HTML5/CSS3: 반응형 웹 디자인
  • JavaScript (ES6+): 동적 인터랙션
  • Inter, Koulen 폰트: 타이포그래피
  • CSS Grid/Flexbox: 레이아웃 시스템

핵심 기능 구현

1. 롤링배너 (Carousel) 구현

메인 이지의 제품 추천 섹션에서 사용된 롤링배너는 순수 JavaScript로 구현함

배운점: CSS Transform을 활용한 성 최적화

// main.js
class RollingBanner {
constructor() {
this.currentIndex = 0;
this.items = document.querySelectorAll('.banner-item');
this.totalItems = this.items.length;
this.autoPlayInterval = null;
this.init();
}

init() {
this.showCurrentItem();
this.startAutoPlay();
this.bindEvents();
}

showCurrentItem() {
this.items.forEach((item, index) => {
item.style.transform = `translateX(${(index - this.currentIndex) * 100}%)`;
});
}

next() {
this.currentIndex = (this.currentIndex + 1) % this.totalItems;
this.showCurrentItem();
}

prev() {
this.currentIndex = (this.currentIndex - 1 + this.totalItems) % this.totalItems;
this.showCurrentItem();
}

startAutoPlay() {
this.autoPlayInterval = setInterval(() => this.next(), 3000);
}

bindEvents() {
// 호버 시 자동 재생 정지
const container = document.querySelector('.rolling-banner-container');
container.addEventListener('mouseenter', () => clearInterval(this.autoPlayInterval));
container.addEventListener('mouseleave', () => this.startAutoPlay());
}
}

2. 무한 스크롤 페이지네이

검색 결과 페이지에서 사용된 무 스크롤은 "Load More" 버튼 방식으로 구현

배운 점: 서버 클라이언트 간의 상태 동기화, 로딩 상 관리, 에러 핸들링

// normal_search.js
class SearchPagination {
constructor() {
this.currentPage = 1;
this.hasMoreData = true;
this.isLoading = false;
this.ITEMS_PER_PAGE = 30;
this.currentSearchKeyword = '';
}

async loadMoreResults() {
if (this.isLoading || !this.hasMoreData || !this.currentSearchKeyword) return;
 
this.isLoading = true;
this.showLoadingIndicator();
 
try {
const response = await fetch(
`/search/normal/?keyword=${encodeURIComponent(this.currentSearchKeyword)}&page=${this.currentPage}&limit=${this.ITEMS_PER_PAGE}`,
{
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}
);
 
const data = await response.json();
 
if (data.foods.length === 0) {
this.hasMoreData = false;
this.hideLoadMoreButton();
} else {
this.appendSearchResults(data.foods);
this.currentPage++;
 
if (data.foods.length < this.ITEMS_PER_PAGE) {
this.hasMoreData = false;
this.hideLoadMoreButton();
}
}
} catch (error) {
console.error('검색 중 오류가 발생했습니다:', error);
alert('검색 중 오류가 발생했습니다.');
} finally {
this.isLoading = false;
this.hideLoadingIndicator();
}
}
}

3. 로그인 모달창 시스템

사용자 인증을 위한 모달창 시스템을 구

배운 점: CSS 애니메이과 JavaScript를 활용한 부드러운 사용자 경험 구현

<!-- login_modal.html -->
<div class="login-modal" id="loginModal">
<div class="modal-content">
<div class="modal-header">
<h2>로그인이 필요합니다</h2>
<button class="close-btn" onclick="closeLoginModal()">×</button>
</div>
<div class="modal-body">
<p>이 기능을 사용하려면 로그인이 필요합니다.</p>
<div class="login-options">
<a href="{% url 'account_login' %}" class="btn-primary">로그인하기</a>
<a href="{% url 'account_signup' %}" class="btn-secondary">회원가입</a>
</div>
</div>
</div>
</div>


주요 기술적 이슈와 해결 과정

1. 파비콘 캐 

배포 환경에서 파비콘 변경이 즉시 반영되지 않는 문를 겪었습니다.문제: 브라우저가 파비콘을 강력하 캐싱하여 변경사항이 반영되지 않음

배운점: 정적 파일의 캐시 무효화, 버전 파라미터 활용

2. 페이지네이션 로직 오류

한 스크롤에서 마지막 페이지에서도 "Load More" 버튼이 표시되는 문제를 겪었습니다.문제: 서버에서 has_more 플래그를 제대로 전달하지 않음

# views.py
def normal_search(request):
# ... 기존 코드 ...
total_count = filtered_list.count()
has_more = end_index < total_count
 
return JsonResponse({
'foods': foods_data,
'has_more': has_more,
'total_count': total_count
})

배운 점: 서버 클라이언트 간의 데이터 일관성 유지의 중요

프로젝트를 통해 느낀점

처음에 git 다루는 것도 어색하고, 에러나 충돌이 났을 때 정말 당황하고 무서워했던 기억이난다.
지금도 아니라고 할 수는 없지만, 처음보다 당황하지 않고 문제 발생시 해결능력이 많이 늘었다는 것을 느꼈다.

또한 추상적으로만 알고 있었던 CRUD를 프로젝트를 통해 직관적으로 이해할 수 있게 된 것 같다.

이 외에도 다른 사람과 함께 협업을 한다는 것 자체가 처음이었고,

다음에 또 협업이 주어진다면 어떤식으로 해나가야 하는지에  대한 지표가 됐다.