import-Hプロジェクト中期回顧


import-Hプロジェクト

import-Hは、4人のフロントと2人のバックエンドからなるチームが開発しているプロジェクトです.notion : https://jamong1.notion.site/Import-H-d4f69f3c20ce4a22a5b0f6ac952da2d2
過去1年間で約30人がプログラミング研修を行い、1人で管理者としての役割を担うなど、注意すべき点も多く、学習チームメンバーの管理にも不足点が多かった.この問題を解決するために、学習サイトを作成しました.

アイテムのプレビュー


ログイン/登録


ログインと登録コストが各inputに入力された値を確認し、フォーマットが正しくないとコミットできないようにします.

メイン画面


バナーセクションでは、管理者が直接追加、削除できます.主に、説明したい情報を共有するために使用されます.
はい、文章は最新の順序で伝わります.

掲示板


掲示板は全部で3つに分かれている.
  • qna掲示板
    伝言板
  • 自由フォーラム
    自由コミュニケーションフォーラム
  • 個人活動掲示板
    それぞれの学習内容の掲示板をアップロード
  • 投稿


    投稿には、「いいね」機能とコメント機能が追加されています.

    パブリケーションの作成/変更


    投稿はtoast-uieditorを使って文章を書くことができます.また、イメージアップロード機能をより友好的にするために、Velogのイメージアップロードフォーマット(base 64からなるイメージをサーバに送信することによって格納されたサーバアドレスを取得する)も参照される.

    (開発中)


    このほか、開発中のページには、プロファイルの閲覧、ページの変更、学習ページなどがあります.

    プロジェクトで考えた部分。


    redux-persistインポート


    Reduxがリフレッシュされるとstoreの情報が失われます.したがって、継続的なストレージが必要な場合は、localStorageやsessionStorageなどのローカルストレージに情報を格納し、ロードして使用する必要があります.
    useEffectは毎回isauthをチェックするため,=>redux-persistを導入した.

    redux-toolkit非同期処理


    以前はredux-toolkitのsliceファイルに非同期関数を作成して処理していました.しかし直感的ではなく,非同期処理に基づいてactionを分離する必要がある.
    従って、createAsyncThunkを用いて非同期処理部が変更される.
    しかし、ここでの問題は、グローバルステータスを管理するreduxが、グローバルステータスよりも非同期を管理していることです.

    非同期で長すぎるslice、この悩みは私一人ではありません.
    =>https://techblog.woowahan.com/6339/倍民の技術ブログによると、私と同じように悩み、react-queryを使って非同期処理方式を変え、storeを楽にしたという.
    現在、非同期処理はcreateAsyncThunkが使用されているが、今後のプロジェクトがメンテナンス段階に入ると、RTK-queryが非同期処理を担当するために徐々に使用される.

    react-testing-library


    実際、プロジェクトを行う過程で、テストコードを書いたことがないので、少し怖くなりました.
    テストするものが多すぎるので、私たちのプロジェクトを見てみました.しかし、経験を増やすためにテストを導入し、現在は一部のテストが行われている.(navbar, comment)

    userSelectorとuserDispatchをテストする方法を見つけるのに長い時間がかかりました.
    テストは、ドキュメントに記載されている効果よりも利点を示します.
    テストを書く過程で、私はもう一度コードを考えて、このようにコードを考えて、私は多くの私が逃した状況と間違ったコードを発見することができます.
    また,テストを効率的に記述する方法を考えると,コンポーネントの量が大きすぎることに気づき,テスト量を減らす作業を行った.
    その結果,1つの素子で演じられる役割は以前に比べて減少した.

    プロジェクトディレクトリ


    プロジェクトといえば、プロジェクトディレクトリの構成を落とすことはできません.プロジェクトディレクトリはPagesとComponentで区切られていることが多く、まだ熟練していないため、あまり満足していないのかもしれません.(少し汚れて見える)

    これは、反応設計原則관심사에 따라서 코드를 분리하고 단일 책임을 가지는 컴포넌트를 만들어야 한다を正しく遵守していないことによる問題であり、現在素子分離作業が行われている.

    apiドキュメント


    今回のプロジェクトまではapiを直接バインドするのは1回しかなかったので、とても心配です.しかし、以前のプロジェクトで出会ったapiによるコミュニケーションの問題を知っていたので、今回はapiドキュメントを作成してプロジェクトを行いました.

    APIドキュメントはバックグラウンドリーダーとともに作成されると,大きな発展を遂げることができ,まず,フロントのアクションフローだけでなくバックエンドのアクションフローでもある.
    また、追加する必要がある新しいapiやapiに含まれるリクエストを変更する場合、これらの情報はバックエンドやフロントエンドで共有されるのではなく、ドキュメントで共有されることが最も魅力的です.
    これにより、apiの作成ミスによりプログラムが実行されないエラーが大幅に低減される.

    レコードアイテム


    コンセプトでこれまで行われた会議、apiドキュメント、エラー解決方法、プロジェクトの進行中に助けられたリンクをすべて記録します.最初は面倒でしたが、時間が経つにつれて、プロジェクトはますます発展し、以前出会った問題は解決しやすく、共有しやすいので、後で他のプロジェクトを行っても、このようなドキュメント化作業は必ず行われます.

    https://jamong1.notion.site/Import-H-d4f69f3c20ce4a22a5b0f6ac952da2d2

    db設計


    実際、バックエンドの経験があまりないため、このプロジェクトを行う際にバックエンド会議によく参加し、バックエンドのプロセスをある程度体験しました.その中で最も印象的なのはdb設計時間です.前学期にdbを勉強したので、すぐにdbを設計できると思っていましたが、思ったより考えたことが多かったです.最も代表的な例は,掲示板と投稿dbを分離する理由を考慮した場合である.
    以前私たちが設計したdbは掲示板表を別々に設計していませんでしたが、より規模の大きいサイトのdb設計から見ると、掲示板表と投稿表は別々に使用されています.これらの理由は検索速度の向上と正規化であり,我々のプロジェクトも対応する内容に従ってdbを設計した.

    割当項目


    フロントのメンバーが4人いて、一人一人実力が違うので、どのように配属すればいいのか悩んでいます.結果、各チームメンバーの役割
  • コード構造設計(Redux)と全面協調
  • 担当側素子
  • 設計総監
  • 部分関数と論理
  • 文書の重要性


    正式な書類の大部分は英語で、以前はブログの文章をたくさん見ました.
    しかし、プロジェクトを行う上で困難に直面し、この問題を解決するために、正式な書類をよく読んだ.
    驚くべきことに、公式文書には多くの答えがある.

    ルールの定義


    コミットメッセージルールは以前は定められていなかったが、コミットの積み重ねによりaddPost 개발が見られると、新機能が追加されたのか性能が向上したのか分からない.このため、コミット・メッセージ・ルールが追加されました.

    axios Instance


    プロジェクトでは、ログインにJWTが使用されています.
    JWTが検証要求を必要とする場合、accessTokenをヘッダに転送する必要があります.
    また、accessTokenが期限切れになった場合はrefreshTokenを再発行する必要がありますが、これらのプロセスを非同期処理ごとに統一的に記述するのは面倒です.
    従って、これらの共通の辞書機能は、インスタンスによって実現される.
    Axios Instaceは複数の参考資料で構成されています.
    検証が必要なAPIリクエストを送信する場合は、AxiosInstanceではなくAxiosを使用してこれらの機能を自動的に実行します.
    import axios from "axios";
    import jwt_decode from "jwt-decode";
    import dayjs from "dayjs";
    
    const baseURL = "http://localhost:8090";
    
    let authTokens = localStorage.getItem("authTokens")
      ? JSON.parse(localStorage.getItem("authTokens"))
      : null;
    
    const axiosInstance = axios.create({
      baseURL,
    });
    
    axiosInstance.defaults.headers.common[
      "Authorization"
    ] = `${authTokens?.accessToken}`;
    
    axiosInstance.interceptors.request.use(async req => {
      console.log("interceptor is working");
      req.headers.Authorization = `${authTokens?.accessToken}`;
      if (!authTokens) {
        authTokens = localStorage.getItem("authTokens")
          ? JSON.parse(localStorage.getItem("authTokens"))
          : null;
        req.headers.Authorization = `${authTokens?.accessToken}`;
      }
    
      const user = jwt_decode(authTokens.accessToken);
      let isExpired = dayjs.unix(user.exp).diff(dayjs()) < 1;
      console.log("isExpired", isExpired, dayjs.unix(user.exp).diff(dayjs()));
      if (!isExpired) {
        return req;
      } else {
        const response = await axios.post(`${baseURL}/v1/reissue`, {
          accessToken: authTokens.accessToken,
          refreshToken: authTokens.refreshToken,
        });
    
        localStorage.setItem("authTokens", JSON.stringify(response.data.data));
        authTokens = response.data.data;
        req.headers.Authorization = `${authTokens?.accessToken}`;
        return req;
      }
    });
    
    export default axiosInstance;
    
    // https://github.com/divanov11/refresh-token-axios-interceptors/blob/master/frontend/src/utils/axiosInstance.js 참고함