【ITスクール最優秀卒業・ポートフォリオ①】チームプロジェクトPERIONの説明(詳細説明はURL添付)
はじめに
お久しぶりです!
チームプロジェクトが忙しくなってから、記事作成を中止し、終わってからも約20日間のリフレッシュ時間を持ったことで投稿が結構遅くなりました。
今日は、報告したいことが二つあります。
まず、チームプロジェクトは無事に終わり、バグがいくつかありますが、みんなが納得いくような目標達成もできました。最終の3日は毎日徹夜でしたが、みんなで頑張ったおかげでできたと思います。チームプレーの良い点も大変さも色々勉強できた密度のある時間でした。
次は、ITスクールの話になりますが、一応、最優秀卒業生という形で、卒業していただきました。
40人の中で、18人が卒業し、その中での1位でした!
表彰と成績点数の存在すら知らなかったのですが、自分の名前が呼ばれた際は、正直今まで苦労したことが思い出し、泣けそうな気分になりましたが、男なので、我慢しました。
勉強だけに集中したので、遠距離中の彼女を寂しくしたり、周りにもたくさんの助けてもらって申し訳なかったのですが、この場を借りてもう一度お礼を言いたいと思います。
家族、彼女、メンターさん、チーム員全員、先生、友達、いつも記事を読んでくださったアイリさんにも心から感謝の言葉も申し上げます。
プロジェクト紹介
今日は、今までのプロジェクトについての簡単な紹介(githubのreadme.mdの補足)や経過、学んだ点などを投稿したいと思います。
Project PERION
当プロジェクトは「PERION」といったメンズファッション通販サイトです。
通販サイトを選定した理由としては、CRUD, session, ファイル処理、マークアップなどITスクールで学習したものを活かすことができ、「基本に充実する」といった共通の目的に一致したためです。
PERIONは韓国のMMORPGに登場する戦士の村で、「戦士のように、強い気持ちで生きていきたい」といった気持ちを込め、名付けました。
こちらがポートフォリオになります。
プロジェクト概要
-
プロジェクト名: Perion
-
プロジェクト期間: 2023.12.05-2024.01.08 (約1か月)
-
プロジェクト技術
- Backend : Java17, MySQL, MyBatis, SpringBoot, Gradle, Thymeleaf, Lombok
- Frontend : Html5, Css3, JavaScript, SweetAlert2
-
Environment : IntelliJ Idead, Visual Studio Code, Figma, Git, GitHub, ERDCloud, Google SpreadSheets
-
チームメンバー:
-
私(PM/BE/FE)@HyonHyonKOR
UX/UIデザイン総括 / クライアントページマークアップ・FE / サーバーアーキテクチャ / 会員機能全般 / バリデーションチェック / 認証(Spring Interceptor) -
チーム員1(BE/FE) @swaeluu
UX/UIデザイン / 管理者ページマークアップ・FE / Q&A機能 / カスタマーレビュー機能 / ページング処理 -
チーム員2(BE/FE) @VoiceofSiren
AJAX / 商品関連機能 / 在庫管理機能 / 会員カート機能 / 会員注文機能 / DBA -
チーム員3(BE/FE) @Titan153
お知らせ機能 / ID・PW再設定機能 / マークアップ補助 / 外部API / 参考資料整理 -
チーム員4(BE/FE) @Ainchel
AJAX / 在庫管理機能 / 会員カート機能 / 非会員カート機能 / 非会員注文機能
-
プロジェクト内容(Readmeからでも参考可能)
フロントエンド
- Responsive WEB
最初のページは、viewportのサイズによって、レイアウトが変更されるレスポンシブWEBを具象しました。
今後、indexページのみならず、他のページもmedia queryを活用して、レスポンシブWEBにしたいと思います。
- UX/UI
- Navigationからカテゴリーをすぐ選択できるようにし、ページDEPTHを減らすことでCPRの向上を目指しました。
- 縦が長いページであるため、ユーザーが欲しい情報をすぐ確認できるよう、サイドバーを具象しました。
- より直感的にログインができるよう、IDとパスワードの最低文字数を超えれば、ログインボターンのOpacityが1になるように調節しました。
- AJAX
JavaScriptのfetch、JSON、SpringBootの@ResponseBodyアノテーションなどを活用し、カートを具象しました。
カートページは翻訳機を使う場合、レイアウトが崩れたため、そのまま展示しました。ご了承いただければと思います。
- Rendering
- Indexの5000x3000、4mb以上のJPEG画像を約1900x1000までリサイズし、webpに変換することでレンダリング速度を改善しました。
- 通販サイトの場合、SEO対策が重要であるため、Metaタグを活用しました。
- 一部のscriptにdeferを適用し、htmlのparsingを改善する努力をしました。
- 一部のjsにEvent Delegation通して、不要なEvent Handlerを減らす努力をしました。
バックエンド
- 商品関連
管理者ページから商品・写真・在庫などをDB、resourceフォルダーに登録し、クライアントページからそのデーターを読む形です。
- 注文
- 管理者ページ
売上はペンディング、非会員注文一覧はまだ、バグの問題で紹介することはできませんでした。まだ原因が分からないため、後ほど解決したいと思います。
- 認証(Spring Interceptor)
未認証ユーザーの要請は会員ログインページに、権限があい会員の要請は404エラーページをリターンして、認証を強化しました。
権限外の要請がある場合は、log4jを通して、WARNログを残すようにコードを作成しました。
解決できなかった点:一部のページではInterceptorが適用されない現象があるので、今後改善してみたいと思います。
リファクタリング
- 近いうちにAWSへのdeployを計画中
- 会員登録機能にAJAXを追加し、フロントエンドからもバリデーションチェックを追加
- ページ処理のバグを改善する予定
プロジェクト過程
我々はプロジェクトの過程を振り向き、思い出した三つのキーワードは 「協力」、「協業」、「オブジェクト指向」 でした。
特に、コミュニケーションをすることをとても大事に考え、最初の1週間は会議、共同作業で皆が納得がいくように合意することに時間を費やし、一人は一身上の事情でリモートで参加したので、プロジェクトの最中もdiscordを通して、会議をしました。
このプロジェクトが終わってから感じたことは様々ありました。
一人ではこのような膨大なプロジェクトを終わらせることができなかった点、人を適材適所に配置することの大事さ、協業の効率さなど、プロジェクトを始まる前は多少モヤモヤする気分もありましたが、とても良い経験で良い勉強になったと思います。
当時の気持ちを作成した日記です。
1.協力
早く行きたければ一人で進め、遠くまで行きたければ、みんなで進め
事前に前出した通り、皆が意見を出して、合意して納得がいくことが大事だと考え、全員企画を行いました。行同作業のためという理由もありますが、みんなの意見と熱意が入った方が、自分が発言したことに対しての責任感に繋がると考えました。
また、個人的にもみんなで成長し、工夫してみたい気持ちもあったので、全員企画のみは拘りとしてプロジェクトを進みました。
以下はチーム員、全員がした会議録と企画の内容になります。
技術選定
チームプロジェクトの技術を選定する際いに、SSR、MyBatis、ライブラリなど色々なことを視野に入れ、何をTrade offしました。
UX/UIデザイン
YoutubeからFigmaを独学し、4倍数デザイン、12Grids 1320pxを意識ながら、クライアントページのデザインおよびワイヤフレームを作成しました。また、UXの改善のため、session(depth)を減らす工夫をし、無駄なプロセスを減らす努力をしました。
※ワイヤフレームの詳細はこちらをご覧ください(figma)!※
DB、ERD設計
チーム全員で、協力して企画した内容をもとにERD、DBを設計しました。1次正規形のデーター、みんなで各々イメージしているDBテーブルをざっくり作成しながら、中間テーブルで多対多関係のテーブルを2次・3次正規形にしました。
1NF、2NFまでは理解できましたが、3NFをしっかり理解して適用することが難しかったです!
本来ならカテゴリごとにS、M、Lサイズがあり、アクセサリーのみサイズがなかい企画でしたが、そうなれば在庫テーブルとうまく結ぶことが複雑になりました。
最終的にはアクセサリーを除きましたが、リソースの制限があったので、一部は非正規化を通して、フィールドを追加したり、統合しました。
Restful API、PRGパターン
クライアントページ(user page)と管理者(admin)ページのURIを分け、APIを設計しました。
協業の効率性を高め、APIを統一することで、Spring Interceptorを活用するためでした。
※User APIの詳細URL/Admin APIの詳細URL※
2.協業
才能で試合に勝つが、優勝はチームワークと知性で勝ち取る。 -マイケル・ジョーダン-
チームプロジェクトの前には色々ん技術を導入することが重要だと考え、新しい技術を学ぶことに夢中になったのですが、周りの経験者から言われたのは、「協業の能力」 でした。
ITスクールではgitを使わず、kakao talk(韓国のLINE)でコードをアップロードするチームも時々ありそうですが、実務では決してはあってはいけないことで、gitでチームプロジェクトをやり遂げることを第一目標として目指しました。
git
メンターさんからgitの使い方でなく、gitは何か?なぜ使うのかをしっかり教えて頂き、プロジェクトが始まる前はadd, commit, pushをする練習を行いました。originとremoteの違いを直接ぶつかりながら、チーム員全員で3回ぐらいのテストプロジェクトを行いつつ、mergeする練習が終わってから、プロジェクトに入りました。
また、Intelli Jの中でgitを簡単に操作することもできるようですが、アドバイスどおり、IDEを依存せず、Terminalとgit bashを連携し、command語を使用することを大事にしました。
git flow戦略としては、チーム全員が初めてでしたので、機能ことではなく、個人の名前の
initialをrepository名にし、originから分かれたdevelop branchにmergeする戦略を取り、いつも1日2回以上はmergeをし、pullをしました。お互いに担当するところは積極的にコミュニケーションを取りつつ、被らないよう、conflictが最大限起きないような抑える努力をしました。
gitの練習を徹底化した結果、約710回以上のcommitでチームプロジェクトを済ませることができました。他のチームがconflictとgitの理解不足で皆で作成したコードをまるごとなくした大事件もあったので、練習をしたことが良い判断だと思いました。メンターさんのご助言があってからの結果だと思います。
プロジェクトが終わる約2週前からgit commit時のconventionを教えていただき、チーム員全員で使ってみました。
Project Management
spreadsheetsからの会議録、Gannt Chart, API、ワイヤフレームなどもありましたが、各々のコードをどのように集めるか、効果的なスケジュール管理をどうした方が良いのかが悩みでした。以前、個人プロジェクトで大きすぎな目標を立て、優先順位を組まなかったのも原因だと考え、メンターさんから教えていただいたGithubのOrganizaion, Projectを利用し、スケジュール管理をしました。
プロセスは以下のようです。
① MTGから決めた内容をコアー機能のspreadsheetのメモに残す。
② 具象するコアー機能をgithub projectのissueに作成する。
③ github projectのissueごとにspreadsheetを添付し、優先順位、ドメイン(ユーザー、管理者)に分ける。
このように、作業の進行度をリアルタイムで一目で把握できるように、GithubのProjectから管理し、チーム員の実力に合わせ、具象する機能をあり当てました。しかし、既存のProjectは進行度を4段階で管理し、In Progress(進行中)、Done(完了)のように0か100かでしか進行度が把握あできなかったので、その間にCRUD Done(データーのInput/Output)を追加し、CRUDのみで終わらせるか、追加でバリデーションチェックのような機能、例外ハンドリングをするかなどを全体進行度に合わせ、判断しました。
当時作成したGit関連マニュアルの一部です。
3.オブジェクト指向
三斗の珠もつないでこそ宝 -韓国のことわざ-
韓国のことわざではは、そのようなことわざがあります。一個、一個が綺麗な珠だとしても、綺麗に磨き、片づけ、つながなければその価値・力を発揮できないという意味です。
コードを作成する前に、設計をせずに、整えていない状態で入り、クラスとメッソドの役割分断のバランスが良くない場合、後で、クラス全体の修正しなければならなかったりする状況に直面する場合もありますので、色々を工夫しつつ、コーディングに入りました。
SpringBootを独学しながら、Springがオブジェクト指向のため作られたフレームワークといった点とオブジェクト指向のため作られたアノテーションなどを勉強したので、積極的に活用してみたいと気持ちも強かったです。
SpringBoot勉強記録①
SpringBoot勉強記録②
サーバー設計
プロジェクトの特性上、5人が5週間参加する規模のあるプロジェクトでしたので、Modelをservice, repositoryに分離し、Layered Architectureを参考し、Controllerは表現の領域、repositoryをDBアクセス領域に配置し、EntityとDTOにデーター関連オブジェクトを分けました。
SOLID原則のSRPのように、一つのクラス・メッソドには一つの役割のみ与え、特定のクラス、メッソドに依存せず、より柔軟な仕組みを作りたいと考えたからです。
OCP、DIP
拡張可能性のあるプログラムを作成するため、Repositoryの場合、Interfaceを依存し(DIP:具体的なものではなく、抽象的なものに依存する)、ポリモーフィズムにより、代替できる(OCP:変更・修正は閉鎖的、開放・拡張性には開放的) ように設計しました。MyBatisを利用しておりますが、今後JPAも使ってみたいチーム員が多かったことも一つの理由です。
/*会員退会*/
@Transactional
public void withdraw(Long memberNo,MemberDeleteDTO memberDeleteDTO){
Member member = MemberDeleteDTO.MemberDeleteDTOToMember(memberNo,memberDeleteDTO);
memberRepository.findByNo(member.getMemberNo())
.filter(m -> m.getMemberPw().equals(member.getMemberPw()))
.ifPresentOrElse(
m -> memberRepository.deleteByNo(member.getMemberNo()),
() -> { throw new IllegalStateException("パスワードをご確認ください。."); }
);
}
public interface MemberRepository {
void save(Member member);
void update(Member member);
void deleteByNo(Long memberNo);
Optional<Member> findByNo(Long memberNo);
Optional<Member> findById(String memberId);
Optional<Member> findByEmail(String memberEmail);
.
.
.
@Repository
@RequiredArgsConstructor
public class MyBatisMemberRepository implements MemberRepository {
private final MemberMapper memberMapper;
@Override
public void save(Member member) {
memberMapper.save(member);
}
@Override
public void update(Member member) {
memberMapper.update(member);
}
@Override
public void deleteByNo(Long memberNo) {
memberMapper.deleteByNo(memberNo);
}
@Override
public Optional<Member> findByNo(Long memberNo) {
return Optional.ofNullable(memberMapper.findByNo(memberNo));
}
.
.
.
BEM、DRY原則
繰り返されるコードを控えるDRY法則(Don't Repeat Yourself)を参考し、Optionalクラス、Lombokライブラリ、Thymeleafのfragmentsを利用し、フロントエンドの場合、classを利用するBEMでcssをcomponentにする努力をしました。コードの量を減らす、再活用できるような仕組みで時間を節約するためでした。
私のチャレンジ
プロジェクトに挑みながら、勉強になった点を記録します。
Error Handling
例外クラスを作成し、SpringBootのBindingResultと連携しつつ、コードの量を減らし、例外を処理しました。
会員登録ロジックの場合、ID(PK)、携帯番号(UK)、メールアドレス(UK) 、3つのバリデーションチェックが必要な状況でした。
そのため、ServiceオブジェクトからControllerに例外を三回投げる(例外を発生させる)ことになりましたが、その場合、以下のような問題点がありました。
認証(Spring Interceptor)
SpringのInterceptor機能を利用し、認証機能を強化しました。
(会員個人個人にURIとして使われる番号を与え、自分のURI以外のURIにはアクセスを防ぎました。)
Refactoring
AJAX with debouncing
AJAX機能(リアルタイムでIDを確認)を追加し、性能改善のため、debounce機能をlodashライブライを利用し、改善しました。
さいごに
惜しかった点
① バグを完璧に処理することができなかった点です。
認証機能を追加してからできたバグでしたが、1日前に追加した機能でしたので、日程上、解決することができませんでした。
② バックエンド的なことももっとやってみたかったです。
PMとして、意思決定をしたり、チーム員のトラブルを解決することでコーディング時間を確保することが難しく、マークアップ、フロントエンド以外にももっとコードを作成してみたかったです。
(それとも、フロントエンドをもっと勉強してみてもいいかもしれないですね!色々なことに興味があるので、まず経験を重ねてみたい!)
感謝の言葉
初めてのチームプロジェクトで、色々なイレギュラーと計画どおりは進めませんでしたが、決して一人ではできなかった大きなプロジェクトだと思います。
最後の3日は、徹夜の続きでしたが、みんなが助け合い、大変な状況でもチーム員同士大きなトラブルなしで、任されたパートを責任をもって全うしてくれたおかげで目標を達成することができました。
健康問題でリモート参加にしたチーム員さんも手が空いている際に雑務を担当してくれたり、他のチーム員もやる気満々で「これ、必要だな、、どうしよう」と思う際には言わなくても自分で仕事を探して手伝ってくれたおかげでとても助かったと思います。感謝しきれない。
この場を借りてもう一度感謝を伝えたいと思います。
Special Thanks
毎月、貴重な時間を割いて頂き、このプロジェクトのためにも色々なことを教えてくださったメンターさんに感謝します。かならず、恩返しします。
結婚、おめでとうございます。
Discussion
ヒョンモさん! チームプロジェクトお疲れ様です!(^^)/
設計の書類だったり会議録とか、すごい丁寧に残されててびっくりしました...!
そしてReadmeとか読んでみても、いろんなとこに意識向けて作ってたのが伝わってきて感動です~~
またAWSでデプロイできたらみたいです!!!!!
ありがとうございます!!!!!!!!!!ㅠㅠ
チーム員とメンターさんあってのことです。
特にメンターさんと以前あいりさんのポートフォリオがなかったらできなかったと思います!
簡単なリファクタリングだけ終われば、すぐAWSにデプロイします!!
その際にはまた、よろしくお願いいたします。