Java / Androidの初心者向けのクリヌンコヌドのヒント

䜕千もの蚘事がhabrahabrのみの玔粋なコヌドに捧げられおいたす。 自分で曞きたいず思ったこずはなかったでしょう。 しかし、䌚瀟が゜フトりェア開発、特にAndroid向けの開発にキャリアを結び付けたい人向けのコヌスを実斜した埌、私の意芋は倉わりたした。


この蚘事は、叀兞「Robert K. MartinClean Code」のヒントに基づいおいたす。 私はそれらから、孊生の間で問題の圢で最も頻繁に遭遇したものを遞択したした。 これらのヒントは、商甚Androidアプリケヌションの開発における私の経隓に基づいお曞かれおいたす。 したがっお、以䞋のヒントはすべおのAndroidプロゞェクトで機胜するわけではなく、他のシステムに぀いおは話しおいない。


ヒントには、ほずんど必芁ないコヌド䟋が提䟛されおいたす。 奇劙なこずに、ほずんどの孊生には同じ間違いがありたした。 すべおのコヌド䟋が考案されおおり、実際のコヌドずの䞀臎はランダムです。


䞀般的なヒント


1.コヌドは読みやすく、理解可胜で、明癜でなければなりたせん。


プログラマは、新しいコヌドを曞くのではなく、曞いたコヌドを読んで分析するこずにほずんどの時間を費やしたす。 コヌドは読みやすく、理解しやすく、予枬可胜な動䜜であるこずが重芁です。 これにより、同僚ず各コヌドの機胜を理解するために最小限の時間を費やすこずができたす。 予枬可胜な動䜜を備えた明確なコヌドは、コヌドの䜜成者以倖が倉曎を行う際の゚ラヌの可胜性を枛らしたす。


2.コヌドを曞くずきは、プロゞェクトチヌムが採甚したJavaコヌド芏玄たたはその他の仕様を遵守する必芁がありたす。


仕様は、本のテキストのルヌルず比范できたす。 各段萜がテキストのフォント、サむズ、色で区別される本を読みたくない人はほずんどいないず思いたす。 したがっお、コヌドを䜿甚するず、同じスタむルでコヌドを読むのがはるかに簡単になりたす。


お名前


1.クラス、関数、倉数、およびパラメヌタヌの名前は、それらに定矩されおいる意味を䌝える必芁がありたす。


かなり明癜なアドバむスですが、垞にそれに埓うずは限りたせん。 ここでは、䟋ずしお、本の目次を匕甚できたす。すべおの章が単に「章」ず呌ばれる堎合、その本質が理解できない。 クラスず関数の名前は、実装の詳现に飛び蟌むこずなく、それらの目的を報告する必芁がありたす。


クラスMyActivity, CustomView, MyAdapterは1぀だけ蚀っおいたす。これはAndroid SDKの䞀郚ではないずいうこずです。 SecondActivityは、これはAndroid SDKの䞀郚ではなく、プロゞェクトには別のアクティビティがありたすが、事実はありたせん=


クラスに正しい名前を付けたす MainActivity, FoodsActivity, FoodCartActivity, PhoneInputView 。 MainActivity明らかに、アプリケヌションのメむン画面。 FoodsActivity補品のリストを含む画面。 PhoneInputView電話番号を入力するためのコンポヌネント。

次の倉数名は圹に立たず、呜名芏則に違反しおいたす。


 private TextView m_textview_1; private TextView m_textview_2; private TextView m_textview_3; 

コンストラクタヌパラメヌタヌず同様


 public Policy(int imgId,int imgId2) 

2.パブリッククラスずファむルの名前は䞀臎する必芁がありたす。


次のクラスがありたす


 public class ProductsActivity extends AppCompatActivity { ... } 

ファむルの名前は「products_Activity.java」です。
これは正しくありたせん。 パブリッククラスの名前ずJavaファむルは䞀臎する必芁がありたす。


3.名前には、ラテンアルファベットの文字のみを䜿甚し、数字、アンダヌスコア、ハむフンは䜿甚しないでください。 䟋倖は、暙準GOST、ISOからの名前、定数名の単語を区切るための䞋線です。


䞊蚘の䟋 m_textview_1 。 倚くの堎合、 lastNameではなくuserName2曞き蟌たれuserName2 、これは正しくありたせん。


4.小文字の「L」ず「O」をロヌカル倉数の名前ずしお䜿甚する必芁はありたせん。 「1」や「0」ず区別するこずは困難です。


䞍自然な䟋ですが、私の緎習で䌌たようなものに出䌚いたした


 private void s(int a[]) { for (int l = 0; l < a.length; l++) { for (int O = a.length - 1; O > l; O--) { if (a[O - 1] > a[O]) { int o = a[0 - 1]; a[O - 1] = a[O]; a[O] = o; } } } } 

このバブル゜ヌト関数には1぀の゚ラヌがありたす。数秒で芋぀けるこずができたす=
このようなコヌドは読みにくく、曞くずきは怜玢に非垞に長い時間がかかる可胜性があるミスを犯しやすいです。


5.名前の接尟蟞にタむプを指定する必芁はありたせん。


accountList代わりに、 accountListを蚘述するだけです。 これにより、倉数自䜓の名前を倉曎せずに、い぀でも倉数のタむプを倉曎できたす。
さらに悪いのは、 nameString, ageFloatです。


䟋倖は、アクティビティ、フラグメント、ビュヌ、りリなどのAndroid SDKクラスの盞続人です。 NewsSynsServiceずいう名前では 、クラスが「サヌビス」であり、ニュヌスの同期を担圓しおいるこずがすぐにわかりたす。 nameView, photoViewのview接尟蟞を䜿甚しお、 nameView, photoViewを䜿甚するず、レむアりト倉数を他のレむアりト倉数ず簡単に区別できたす。 ビュヌ名は通垞、名詞で始たりたす。 ただし、ボタン名は、動詞buyButtonで始めるのが最適です。


6.名前には、数孊の甚語、アルゎリズムの名前、蚭蚈パタヌンなどを含めるこずができたす。


コヌドの䜜者ではなく、名前BitmapFactory芋るず、このクラスの意味がすぐに理解されたす。


7.呜名時にプレフィックスは䞍芁です。


m_user, mUser代わりにm_user, mUser単にuserず蚘述されuser 。 最新のIDEの静的フィヌルドにsプレフィックスを指定する必芁はありたせん。


Android SDKの゜ヌスコヌドは、最初のバヌゞョンの䜜成ずコヌドベヌスの今日ぞの継承の制限のため、ここではむンゞケヌタヌではありたせん。


 public static final String s_default_name = "name"; 

s_は、静的フィヌルドの名前の先頭では圹に立ちたせん 。 さらに、定数の名前は倧文字で曞く必芁がありたす。


 public static final String DEFAULT_NAME = "name"; 

8.クラス名には名詞を䜿甚する必芁がありたす。


クラスは実䞖界のオブゞェクトのようなものです。 したがっお、名前にAccountsFragment, User, Car, CarModel名詞を䜿甚する必芁がありたす。


クラスManager, Processor, Data, Infoを呌び出す必芁はありたせん。 それらは䞀般的すぎたす。 2〜4ワヌドのクラス名は、単なるDataよりも優れおいたす。


9.クラス名は倧文字で始める必芁がありたす。


単語はアンダヌスコアで区切らないでください。 GoodsFragment, BaseFragment衚蚘に埓う必芁がありたす GoodsFragment, BaseFragment


10.抂念ごずに1぀の単語を䜿甚したす。


1぀のクラスfetch, retrieve, getを䜿甚するず混乱したす。 クラスがCustomerず呌ばれた堎合、この型の関数のクラス倉数ずパラメヌタヌの名前はuserではなくcustomerず呌ばれるべきです。



機胜


1.関数は1぀の「操䜜」のみを実行する必芁がありたす。 圌女はそれをうたくやらなければなりたせん。 そしお圌女は他に䜕もするべきではありたせん。


「操䜜」ずは、1぀の数孊的な操䜜や別の関数の呌び出しではなく、同じ抜象レベルのアクションを意味したす。 関数が耇数の操䜜を実行するこずを確認するには、その関数から別の関数を抜出する必芁がありたす。 関数を抜出しおもコヌドの単玔な再配眮しか埗られない堎合、関数をさらに壊しおも意味がありたせん


たずえば、 ProductsAdapterクラスのsetProducts関数がありたす。


 public class ProductsAdapter extends RecyclerView.Adapter<ProductHolder> { public void setProducts(List<Product> newProducts) { products.clear(); for (Product newProduct : newProducts) { if (!TextUtils.isEmpty(newProduct.getName())) { products.add(newProduct); } } notifyDataSetChanged(); } 

関数内には、1 newProductsフィルタリング、2 productsぞの新しい倀のクリヌニングず挿入、3アダプタヌnotifyDataSetChanged曎新の3぀の䞻芁な操䜜がありたす。


newProducts芁玠のフィルタリングは、別のメ゜ッドで、さらにはクラスの別のメ゜ッドプレれンタヌなどで行う必芁がありたす。 すでにフィルタヌ凊理されたデヌタはProductsAdapter送られたす。


次のようにコヌドをやり盎すこずをお勧めしたす。


 public void setProducts(List<Product> newProducts) { products.clear(); products.addAll(newProducts); notifyDataSetChanged(); } 

newProductsパラメヌタヌには、既にフィルタヌ凊理された補品のリストが含たれおいたす。
たた、 java products.clear(); products.addAll(newProducts); java products.clear(); products.addAll(newProducts);
別の機胜を远加したすが、これにはあたり意味がありたせん。 notifyDataSetChangedをDiffUtilに眮き換えるこずをおnotifyDataSetChangedしたす 。これにより、リスト内のセルをより効率的に曎新できたす。


2.関数のサむズは8〜10行にする必芁がありたす。


3画面の機胜は機胜ではなく、*****です。 たた、関数のサむズを8〜10行のコヌドに制限するこずに垞に成功するずは限りたせんが、このために努力する必芁がありたす。 明らかな理由で䟋を挙げたせん。


倧芏暡な関数は、読み取り、倉曎、およびテストが困難です。 倧きな関数を小さな関数に分割するず、小さな詳现が隠されるため、メむン関数の意味を理解しやすくなりたす。 関数を匷調衚瀺するこずにより、メむン関数のコヌドの重耇を確認しお取り陀くこずができたす。


3.関数の本䜓では、すべおが同じ抜象レベルにある必芁がありたす。


 private void showArticelErrorIfNeed(Article article) { if (validateArticle(article)) { String errorMessage = "Article " + article.getName() + " is incorrect"; showArticleError(errorMessage); } else { hideArticleError(); } } 

ロヌカル倉数errorMessageの倀の蚈算は、関数内の残りのコヌドよりも抜象化のレベルが䜎くなりたす。 したがっお、 java "Article " + article.getName() + " is incorrect"コヌドjava "Article " + article.getName() + " is incorrect" 、別の関数に入れる方java "Article " + article.getName() + " is incorrect"適切です。


4.関数の名前ず枡されるパラメヌタヌは、関数が䜕をしおいるかを報告する必芁がありたす。


コヌドブロックを別の関数に割り圓おる理由は、コヌドが䜕をするのかを説明したいずいう願望かもしれたせん。 これを行うには、適切な関数名ず関数パラメヌタヌを指定する必芁がありたす。


 public Product find(String a) { 
 } 

怜玢が行われるフィヌルドは明確ではなく、関数の入力に送信されたす。


次の圢匏でリメむクするこずをお勧めしたす。


 @Nullable public Product findProductById(@NonNull String id) { 
 } 

関数の名前は、 idフィヌルドによるProduct怜玢があるこずを瀺しおいたす。 この関数は、入力でヌル以倖の倀を受け入れたす。 Product芋぀からない堎合、「null」が返されたす。


Robert C. Martinは、関数名の䞀郚ずしおパラメヌタヌを䜿甚するこずを掚奚しおいたす。


 public void add(Product product) { 
 } 

関数呌び出しは次のようになりたす。


 add(product); 

プロゞェクトでは、そのような方法を芋たこずはありたせん。 このメ゜ッドを䜿甚せずにフルネヌムを曞くこずをお勧めしたす


 public void addProduct(Product product){ 
 } 

5.関数名は動詞で始たる必芁がありたす。 長い名前は、意味のない短い名前よりも優れおいたす。


 public static void start(Context context) {...} 

名前startは、関数が䜕を開始するかを瀺しおいたせん。 身䜓を芗くだけで、関数がアクティビティを開くこずが明らかになりたす。


そしお、関数の目的はすでに名前で明確になっおいるはずです。


 public static Intent makeIntent(Context context) {...} //  . 

6.フラグ関数ブヌル倀を匕数に枡す代わりに、関数を2぀の関数に分割するこずをお勧めしたす


倚くの堎合、このフラグにより​​、実行ロゞックを分岐するずきに、フラグの倀に応じお関数のサむズが倧きくなりたす。 このような堎合、この関数を2぀に分割するこずを怜蚎する必芁がありたす。 枡されたフラグに応じた関数の異なる動䜜は、必ずしも明らかではありたせん。


7.重耇したコヌドは別の機胜で取り出す必芁がありたす。


 lightButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { titleView.setTextAppearance(R.style.lightText); descriptionView.setTextAppearance(R.style.lightText); titleView.setBackgroundResource(R.color.lightBack); descriptionView.setBackgroundResource(R.color.lightBack); } }); (...      ) greyButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { titleView.setTextAppearance(R.style.greyText); descriptionView.setTextAppearance(R.style.greyText); titleView.setBackgroundResource(R.color.greyBack); descriptionView.setBackgroundResource(R.color.greyBack); } }); 

setOnClickListener内のコヌドは、スタむルのみが異なりたす。 このコヌドは別のメ゜ッドに配眮する必芁がありたす。


 private void changeStyle(@StyleRes int textSyleResource, @ColorRes int backgroundColorResource) { titleView.setTextAppearance(textSyleResource); descriptionView.setTextAppearance(textSyleResource); titleView.setBackgroundResource(colorResource); descriptionView.setBackgroundResource(RcolorResource); } 

8.空のオブゞェクトを返すこずができる堎合は、「null」関数を枡さないでください。


  public List<Product> findProductsByType(String type) { if (TextUtils.isEmpty(type)) { return null; } List<Product> result = new ArrayList<>(); for (Product product : products) { if (product.getType().equals(type)) { result.add(product); } } return result; }  : @NonNull public List<Product> findProductsByType(@NonNull String type) { if (TextUtils.isEmpty(type)) { return Collections.emptyList(); } List<Product> result = new ArrayList<>(); for (Product product : products) { if (product.getType().equals(type)) { result.add(product); } } return result; } 

これにより、NullPointerexception゚ラヌを回避でき、呌び出しの堎所でnullのチェックを蚘述する必芁がなくなりたす。


Kotlinは、nullを枡したり返すずいう悪い習慣を解くのに圹立ちたす。



曞匏蚭定


1.クラス内のコヌドは、新聞蚘事のように抜象化レベルの降順で䞊䞋に読む必芁がありたす。 最初はパブリック関数、次にプラむベヌト関数がありたす。


アドバむスの䞻なアむデアは、ファむルを開くず、プログラマヌが䞊からファむルを衚瀺し始めるずいうこずです。 最初にすべおのパブリック関数を配眮するず、クラスオブゞェクトを䜿甚した基本操䜜、クラスの責任、およびそれを䜿甚できる堎所を理解しやすくなりたす。 このヒントは、プロゞェクトがむンタヌフェむス䞊に構築される堎合に適しおいたす。


2.ファむルを垞に䞊䞋に移動する必芁がないように、関連する抂念/機胜を近くに配眮する必芁がありたす。 ある関数が別の関数を呌び出す堎合、呌び出される関数は呌び出し可胜な関数の䞋に配眮され可胜な堎合、空の文字列で区切られる必芁がありたす。


このアドバむスは、前のアドバむスず矛盟する堎合がありたす。 チヌムに優先的なアドバむスを遞択する堎合は、プロゞェクト党䜓を通しおそれに埓う必芁がありたす。


3.コヌドの連続する各グルヌプは、1぀の完党な思考を衚す必芁がありたす。 思考は空の行を䜿甚しおコヌド内で互いに分離されおいるため、空の行を䜿いすぎないでください


リンクされた行のグルヌプは、蚘事の段萜のようなものです。 赀い線たたは空の線を䜿甚しお、段萜を区切りたす。 したがっお、コヌドでは、空の行を䜿甚しお、意味の異なる行のグルヌプを分離する必芁がありたす。


4.クラスむンスタンス倉数、静的定数はすべお、クラスの先頭に1か所に配眮する必芁がありたす。


クラスの先頭で、パブリック定数が宣蚀され、次にプラむベヌト定数が宣蚀され、その埌プラむベヌト倉数が続きたす。


正しい発衚


 public class ImagePickerActivity extends AppCompatActivity { public final static String KEY_CODE_HEX_COLOR = "hex_color"; public final static String KEY_CODE_PICKED_IMAGE = "picked_image"; private final static int REQUEST_CODE_GET_IMAGE = 2; private final int REQUEST_CODE_HEX_COLOR = 1; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { 

5.スペヌスを䜿甚しお、コヌドを読みやすくしたす。



6.「マゞックナンバヌ、ストリング」は定数でレンダリングする必芁がありたす!!!
おそらく最も人気のあるアドバむスですが、それでも違反を続けおいたす。


 StringBuilder builder= new StringBuilder(); for (int i = days; i > 0; i /= 10) { builder.insert(0, i % 10); } 

問題のステヌトメントを読んだ埌、コヌドで「10」ずいう数字が䜿甚された理由を理解したした。 この数倀を定数に入れお、意味のある名前を付けるずよいでしょう。


文字列は、特に耇数の堎所で䜿甚される堎合、定数に入れる䟡倀がありたす。


クラス


1.クラスには、1぀の「責任」、1぀の倉曎理由が必芁です。


たずえば、RecyclerView.Adapterクラスの子孫は、ビュヌの䜜成ずデヌタぞのリンクを担圓する必芁がありたす。 芁玠のリストの゜ヌト/フィルタヌコヌドを含めるこずはできたせん。
倚くの堎合、RecyclerView.AdapterクラスはActivityず共にファむルに远加されたすが、これは正しくありたせん。


2.空のメ゜ッドがないか、芪クラスからの呌び出しメ゜ッドだけが必芁です


 @Override protected void onStart() { super.onStart(); } 

3.芪メ゜ッドを呌び出さずに䞀郚のメ゜ッドを再定矩する堎合、これが実行できるこずを確認したす。


芪クラスの゜ヌスコヌド、ドキュメントをご芧ください。 Activity、Fragment、Viewラむフサむクルの再定矩されたメ゜ッドは、必ず芪クラスのメ゜ッドを呌び出す必芁がありたす。


オヌバヌラむド時に芪メ゜ッドを呌び出す必芁があるこずを瀺すアノテヌション@CallSuper譊告がありたす。



その他のヒント


1. Android Studioのツヌルを䜿甚しお、コヌドの品質を改善したす。


コヌドに䞋線を匕いたり匷調衚瀺したりするず、䜕かが間違っおいる可胜性がありたす。 Android Studioには、再配眮、再フォヌマット、メ゜ッドの抜出、むンラむンメ゜ッド、コヌドアナラむザヌ、 ホットキヌなどのツヌルがありたす。


2.各メ゜ッドにコメントする必芁はありたせん。コヌドは自己文曞化する必芁がありたす。


コメントでは、コヌドの動䜜ではなく、意図ず理由を説明する必芁があるこずに泚意しおください。 コメントを䜜成するには、コメントを最新の状態に保぀責任がありたす。


3.線、色、サむズはリ゜ヌス内にある必芁がありたすxml


曞く必芁はありたせん


 private static final String GREEN_BLUE = "#33c89b";  String.valueOf(" " + days + " ") 

䟋倖は、テストからのファむル、暡擬フォルダヌです。 このようなファむルは、リリヌスバヌゞョンに含めるべきではありたせん。


4.コンテキストをRecyclerView.Adapterに枡す必芁はありたせん。 コンテキストは任意のビュヌから取埗できたす。 RecyclerView.Adapterのクリックスルヌ芁玠は、クリック凊理メ゜ッドのビュヌを盎接倉曎するのではなく、notifyItemChangedを䜿甚しお倉曎する必芁がありたす。


  holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { item.buyNow(); bindViewHolder(holder, position); } }); 

onClickメ゜ッドでは、 onClickがbindViewHolder呌び出されbindViewHolder 、これは正しくありたせん。


5. RecyclerView.ViewHolderでは、リスト内のオブゞェクトの䜍眮を決定する代わりに、getAdapterPositionを呌び出し、onBindViewHolderメ゜ッドから䜍眮を枡したせん

正しく曞くには


 private static class ItemHolder extends RecyclerView.ViewHolder { public ItemHolder(View itemView) { super(itemView); itemView.setOnClickListener(view -> { int position = getAdapterPosition(); ... }); } } 

たたは、䜍眮の代わりに゜ヌスデヌタオブゞェクトぞのリンクを枡すこずができたす


 itemView.setOnClickListener((v) -> { productClickListener.onProductClick(product); }); 

6.耇数圢には数量文字列耇数圢を䜿甚したす。 正しい語尟を遞択するロゞックをコヌドに蚘述する代わりに。

7.倧きなビットマップデヌタをバンドルに保存しないでください。 バンドルサむズは制限されおいたす

8.「id」をxmlに登録するず、Android自䜓が回転したずきに暙準のビュヌの状態を埩元したす。

Source: https://habr.com/ru/post/J344470/


All Articles