トーク:良いバックエンドにはどのような良い習慣が必要ですか?

序文

卒業して3年近くになりますが、前後に数社で働き、色々な同僚と出会いました。優れた、ごみ、魅力のない、逃げ出したいなど、あらゆる種類のコードを見てきました。この記事では、優れたバックエンドJava開発に必要な優れた開発習慣を記録します。

合理的なディレクトリ構造を分割する

従来のMVCモデルの影響を受ける従来の方法では、ほとんどの場合、コントローラー、サービス、マッパー、エンティティのいくつかの固定フォルダーを追加し、無制限に追加します。最終的に、サービスフォルダーの下には数十または数百のサービスクラスがあります。ビジネスモジュールを区別することはまったく不可能です。正しい方法は、書き込みサービスの上位層に新しいモジュールフォルダーを作成し、moodlesフォルダーの下にさまざまなビジネスに応じてさまざまなパッケージを作成し、これらのパッケージの下に特定のサービス、コントローラー、エンティティ、列挙型パッケージを書き込むか、分割を続けることです。

今後、開発版を繰り返す場合でも、パッケージを分解し続けることができれば、分解し続けることができ、プロジェクトのビジネスモジュールがはっきりと見えます。その後のマイクロサービスの解体も簡単です。

メソッドパラメータのカプセル化

メソッドに正式なパラメータが多すぎる場合は、オブジェクトをカプセル化してください...以下は、このようなコードの記述を教えてくれた否定的な教材です。

public void updateCustomerDeviceAndInstallInfo(long customerId, String channelKey,
                   String androidId, String imei, String gaId,
                   String gcmPushToken, String instanceId) {}
复制代码

オブジェクトを書く

public class CustomerDeviceRequest {
    private Long customerId;
    //省略属性......
}
复制代码

なぜこのように書くのですか?たとえば、メソッドはクエリに使用されますが、将来クエリ条件を追加する場合、メソッドを変更する必要がありますか?メソッドパラメータリストは、追加するたびに変更する必要があります。オブジェクトをカプセル化します。将来追加するクエリ条件の数に関係なく、オブジェクトにフィールドを追加するだけで済みます。そして重要なのは、コードも非常に快適に見えることです!

ビジネスロジックをカプセル化する

「たわごとの山」を見たことがあれば、深い気持ちになります。このような方法では、数千行のコードを記述でき、話すルールもありません...担当者は、このビジネスはあまりにも複雑で、それを改善する方法はありません、そしてそれは実際には怠惰の言い訳です。ビジネスがどれほど複雑であっても、合理的な設計とパッケージ化を使用して、コードの可読性を向上させることができます。以下は、上級開発者(上級開発者を装って)によって書かれた2つのコードです。

@Transactional
public ChildOrder submit(Long orderId, OrderSubmitRequest.Shop shop) {
    ChildOrder childOrder = this.generateOrder(shop);
    childOrder.setOrderId(orderId);
    //订单来源 APP/微信小程序
    childOrder.setSource(userService.getOrderSource());
    // 校验优惠券
    orderAdjustmentService.validate(shop.getOrderAdjustments());
    // 订单商品
    orderProductService.add(childOrder, shop);
    // 订单附件
    orderAnnexService.add(childOrder.getId(), shop.getOrderAnnexes());
    // 处理订单地址信息
    processAddress(childOrder, shop);
    // 最后插入订单
    childOrderMapper.insert(childOrder);
    this.updateSkuInventory(shop, childOrder);
    // 发送订单创建事件
    applicationEventPublisher.publishEvent(new ChildOrderCreatedEvent(this, shop, childOrder));
    return childOrder;
}
复制代码
@Transactional
public void clearBills(Long customerId) {
    // 获取清算需要的账单、deposit等信息
    ClearContext context = getClearContext(customerId);
    // 校验金额合法
    checkAmount(context);
    // 判断是否可用优惠券,返回可抵扣金额
    CouponDeductibleResponse deductibleResponse = couponDeducted(context);
    // 清算所有账单
    DepositClearResponse response = clearBills(context);
    // 更新 l_pay_deposit
    lPayDepositService.clear(context.getDeposit(), response);
    // 发送还款对账消息
    repaymentService.sendVerifyBillMessage(customerId, context.getDeposit(), EventName.DEPOSIT_SUCCEED_FLOW_REMINDER);
    // 更新账户余额
    accountService.clear(context, response);
    // 处理清算的优惠券,被用掉或者解绑
    couponService.clear(deductibleResponse);
    // 保存券抵扣记录
    clearCouponDeductService.add(context, deductibleResponse);
}
复制代码

実際、この2つのコードのビジネスは非常に複雑で、内部的には5万件の作業が保守的に行われていると推定されますが、レベルの異なる人々による記述はまったく異なります。このコメント、このビジネスの分割を称賛する必要があります。とメソッドのカプセル化。大企業には複数の中小企業があります。さまざまな企業がさまざまなサービス方法を呼び出すことができます。フローチャートなどの関連ドキュメントがなくても、引き継ぐ人はビジネスをすばやく理解できます。一次開発者によって作成された多くのビジネス方法は以前のものです。コードの行はビジネスA用、次のコード行はビジネスB用、次のコード行はビジネスA用です。ビジネス呼び出しの間にネストされたユニットロジックも多数あり、非常に混乱し、多くのことがあります。コードの。

コレクションタイプが空でないことを確認する正しい方法

多くの人はコレクションを判断するためにこのようなコードを書くのが好きです

if (list == null || list.size() == 0) {
  return null;
}
复制代码

もちろん、このように書くことを主張しても問題はありません...しかし、不快に感じないでください。フレームワーク内のjarパッケージには、org.springframework.util.CollectionUtils、comなどのコレクションツールクラスがあります。 baomidou.mybatisplus.core.toolkit.CollectionUtils。後でこのように書いてください

if (CollectionUtils.isEmpty(list) || CollectionUtils.isNotEmpty(list)) {
  return null;
}
复制代码

コレクションタイプの戻り値はnullを返しません

ビジネスメソッドがコレクションタイプを返す場合、nullを返さないでください。正しい操作は空のコレクションを返すことです。mybatisのリストクエリを見ると、クエリされた要素がない場合、nullではなく空のコレクションが返されます。それ以外の場合、呼び出し元はNULLの判断を下す必要があります。これは、ほとんどのシナリオのオブジェクトにも当てはまります。

マッピングデータベースの属性に基本タイプを使用しないようにしてください

int / longなどの基本的なデータ型は、メンバー変数としてデフォルトで0であることは誰もが知っています。mybatisplusやmybatisなどのORMフレームワークを使用することが一般的になりました。挿入または更新するときに、データベースをデフォルト値で簡単に挿入および更新できます。以前の開発を断ち切りたいのですが、リファクタリングされたプロジェクトのエンティティクラスはすべて基本的なデータ型です。その場でひびが入った...

包装判定条件

public void method(LoanAppEntity loanAppEntity, long operatorId) {
  if (LoanAppEntity.LoanAppStatus.OVERDUE != loanAppEntity.getStatus()
          && LoanAppEntity.LoanAppStatus.CURRENT != loanAppEntity.getStatus()
          && LoanAppEntity.LoanAppStatus.GRACE_PERIOD != loanAppEntity.getStatus()) {
    //...
    return;
  }
复制代码

このコードの可読性は非常に低く、誰がこれに何が含まれているのかを知っていますか?オブジェクト指向の考え方を使用して、loanAppのオブジェクトにメソッドをカプセル化できますか?

public void method(LoanAppEntity loan, long operatorId) {
  if (!loan.finished()) {
    //...
    return;
  }
复制代码

メソッドはLoanAppクラスにカプセル化されています。つまり、この論理判断の詳細はビジネスメソッドに表示されるべきではありません。

/**
 * 贷款单是否完成
 */
public boolean finished() {
  return LoanAppEntity.LoanAppStatus.OVERDUE != this.getStatus()
          && LoanAppEntity.LoanAppStatus.CURRENT != this.getStatus()
          && LoanAppEntity.LoanAppStatus.GRACE_PERIOD != this.getStatus();
}
复制代码

制御方法の複雑さ

IDEAプラグインCodeMetricsをお勧めします。これは、メソッドの複雑さを示すことができます。メソッド内の式、ブール式、if / elseブランチ、ループなどを計算します。

クリックしてメソッドの複雑さを増すコードを確認すると、適切に参照できます。結局のところ、私たちは通常ビジネスコードを記述します。最も重要なことは、通常の作業を保証することを前提として、他の人にコードをすばやく理解させることです。メソッドの複雑さが10を超える場合は、最適化できるかどうかを検討する必要があります。

@Valueの代わりに@ConfigurationPropertiesを使用してください

@Valueは@ConfigurationPropertiesよりも使いやすいことを推奨する記事を実際に見ました。私はそれを吐き出しました。誤解しないでください。@ConfigurationPropertiesの利点を一覧表示します。

  • プロジェクトのapplication.yml構成ファイルで、Ctrlキーを押しながらマウスの左ボタンを押しながら構成プロパティをクリックすると、構成クラスにすばやく移動できます。構成を作成するときに、自動的に完了してコメントに関連付けることもできます。追加の依存関係org.springframework.boot:spring-boot-configuration-processorを導入する必要があります。

  • @ConfigurationPropertiesは、NACOS構成の自動更新をサポートします。@ Valueを使用すると、自動更新を実現するためにBEANで@RefreshScopeアノテーションが必要になります。
  • @ConfigurationPropertiesは、妥当性確認検証、@ NotNull、@ Length、およびその他のアノテーションと組み合わせることができます。構成検証が失敗した場合、プログラムは起動せず、本番環境で構成が失われるなどの問題が早期に発見されます。
  • @ConfigurationPropertiesは複数のプロパティを挿入でき、@Valueは1つずつしか書き込むことができません
  • @ConfigurationPropertiesは、ネストのレベルがいくつあっても、複雑な型をサポートでき、オブジェクトに正しくマッピングできます。

対照的に、なぜ多くの人が新しいものを受け入れることを躊躇し、ひびが入っているのか理解できません...すべてのspringboot-starterが@ConfigurationPropertiesを使用して構成プロパティを受け取ることがわかります。

ロンボクをお勧めします

もちろん、これは重要なポイントであり、私の習慣は、ゲッター、セッター、toStringなどを省略するために使用することです。

AServiceでBMapperを呼び出さないでください

AService-> BService-> BMapperからフォローする必要があります。各サービスが他のマッパーを直接呼び出すことができる場合、なぜ他のサービスが必要なのですか?古いプロジェクトは、コントローラーからマッパーも呼び出し、コントローラーをサービスとして扱います。

できるだけ少ないツールを書く

文字列、アサートアサーション、IOアップロードファイル、コピーストリーム、Bigdecimalなど、作成するツールクラスのほとんどが目に見えない形で導入したjarパッケージに含まれているため、作成するツールクラスの数を減らしたいのはなぜですか。自分で間違いを書いたり、冗長なクラスを読み込んだりするのは簡単です。

OpenFeignインターフェースの戻り値をラップしないでください

多くの人がインターフェイスの戻り値をResponse...でラップするのが好きな理由がわかりません。コード、メッセージ、成功の各フィールドを追加すると、発信者が次のようになるたびに

CouponCommonResult bindResult = couponApi.useCoupon(request.getCustomerId(), order.getLoanId(), coupon.getCode());
if (Objects.isNull(bindResult) || !bindResult.getResult()) {
  throw new AppException(CouponErrorCode.ERR_REC_COUPON_USED_FAILED);
}
复制代码

これは同等です

  1. クーポンAPIで例外をスローする
  2. クーポンAPIで例外をインターセプトし、Response.codeを変更します
  3. 呼び出し元は、response.codeがFAIELDであるかどうかを判断し、例外をスローします...

サービスプロバイダーに直接例外をスローすることはできませんか?そして、そのようなパッケージ化されたHTTPリクエストは常に200であり、再試行して監視する方法はありません。もちろん、この質問には、インターフェイスの応答本体をどのように設計するかが含まれます。現在、インターネットには主に3つのジャンルがあります。

  • インターフェイスの応答ステータスは常に200です。
  • インターフェイスの応答状態は、HTTPの実際の状態に従います
  • 仏教の発達、指導者が言うことは何をすべきか

反論は受け付けられません。HTTP標準ステータスを使用することをお勧めします。パラメータ検証の失敗を含む特定のシナリオでは、フロントエンドへのトーストに400が使用されます。次の記事では、ユニフォーム200の欠点について説明します。

意味のあるメソッドコメントを書く

後で引き継いだ人が盲目になるのではないかと恐れていたので、このようなコメントを書きましたか...

/**
* 请求电话验证
*
* @param credentialNum
* @param callback
* @param param
* @return PhoneVerifyResult
*/
复制代码

それを書かないか、最後に説明を追加するだけです...そのようなコメントを書いて、IDEAからたくさんの警告を受け取るのは痛いです

フロントエンドと相互作用するDTOオブジェクトの名前

VO、BO、DTO、POとは、それほど詳細にする必要はないと思います。少なくともフロントエンドとやり取りする場合は、クラス名が適切である必要があります。データベースをマップするクラスを直接使用しないでください。フロントエンドに戻るには、多くの不要な情報が返されます。機密情報がある場合は、特別な処理が必要です。

推奨される方法は、フロントエンド要求を受け入れるクラスをXxxRequestとして定義し、応答をXxxResponseとして定義することです。例として注文を取り上げます。更新された注文情報を受け入れて保存するエンティティクラスはOrderRequestとして定義でき、注文クエリ応答はOrderResponseとして定義され、注文クエリ条件要求はOrderQueryRequestとして定義されます。

IDEAに警察を呼ばせないようにしてください

IDEAコードウィンドウに一連の警告が表示されるのを見て非常にうんざりしていて、非常に不快です。警告があるので、コードを最適化できるか、問題があることを意味します。数日前、チーム内で小さな虫を見つけましたが、実は私とは関係ありませんでしたが、同僚が外の商売を見て、なぜ支店が間違っているのかを判断し、一目で問題を一掃しました。

javaの整数リテラルはint型であるため、コレクション内でIntegerになり、stepIdをクリックして、コレクション内でLong型であるlong型であることを確認すると、containsはfalseを適切に返します。タイプ。

警告に注意を払うと、マウスを上に移動してプロンプトを確認できます。これにより、本番環境のバグが1つ少なくなります。

可能な限り新しいテクノロジーコンポーネントを使用する

これはプログラマーが持つべき品質だと思います...とにかく、新しい技術コンポーネントの出現は古い技術コンポーネントの欠陥を解決する必要があり、技術者として時代に遅れないようにする必要があるため、新しい技術コンポーネントを使用するのが好きです~~もちろん、前提は準備をすることであり、考えずにアップグレードすることではありません。最も簡単な例を挙げると、Java 17がリリースされており、新しいプロジェクトではまだDateを使用して日付と時刻を処理しています...まだDateを使用しているのは何歳ですか?

エピローグ

この記事では、私の日々の開発習慣を簡単に紹介します。もちろん、著者自身の意見だけです。とりあえずこれらの点しか考えられないので、後で更新します。


著者:Twilight Enchanting、
リンク:https://juejin.cn/post/7072252275002966030
出典:RareEarthNuggets
著作権は著者に帰属します。商用の再版については、著者に連絡して許可を求め、非商用の再版については、出典を示してください。

おすすめ

転載: blog.csdn.net/wdjnb/article/details/124403326
おすすめ