こんにちは、私の名前はSiTLarです。私は30歳で、自己文書化コードを書いています

私は長い間、コードのコメントのトピックに興味を持っています。 この投稿は 、コードド​​キュメンテーションのイデオロギーを形式化するため偉業です。



一方で、このコメントは正しいですが、一方で、私はそれらにあまり意味がありません。 さらに、私が読んだこれらのプログラミングの本は、この点をどういうわけか省略しているか、少なくともコメントをあまり重視していない。 関数のパラメーター、メソッド、クラスのプロパティなどのすべての記述を説明することが意味をなさない理由を述べたいと思います。



「すべての説明を記述する」という言葉を偶然書いたのは、それが

std::map<std::string, Person*>mapPPersonsNames //map person pointers by names
      
      







どうして私はそのような異端の人生にたどり着いたのでしょうか?



小さい頃、Quick BasicとREXXでプログラミングすることを学びました。 変数a、aa、x1に名前を付けることを軽daしませんでした。 それで、翌日は何もはっきりしなかったので、これは間違いなく悪い考えだということが明らかになりました。 たとえば、money、answer、file_countなど、変数にもう少し意味のある名前を付け始めました。 ある時点で、OS / 2用のプントスイッチャーをプログラムすることにしました。 当然、私はAPIを学ばなければなりませんでしたが、ここでは、自己文書化コードの精神に本当に触発されました。 OS / 2 APIの変数の名前と関数の名前は非常に複雑であるため、説明を読む必要がない場合もありました。 彼らがどのようにパラメータをマークしたかを見るだけで十分でした。 思いついたのは、コメントのすべての情報を直接コードに転送してみませんか?



コードにコメントが必要なのはなぜですか?



これがこの投稿の重要な質問です。 かなり独立した2つのアプリケーションがあります。 まず、これらの要素または他の要素が何をしているのかを何らかの形で理解する必要があります。 これは、同僚が何をどのように理解する必要がある共同開発にも当てはまります。 別のアプリケーションは、エクスポートされたシンボル、クラス、テンプレートの使用方法をライブラリユーザーに伝えることです。



二重作業に時間を費やしたくないので、自己文書化コードを書きます。



気分に合わせて、自由な時間にゆっくりとプロジェクトを移動します。 開発の中断は1か月以上で、ボリュームはまともです。 コードには十分な情報があるため、一部の部品のリファクタリングに問題はありません。 変数や関数にわかりにくい名前を付けると、コメントがあっても何が起こっているのかを把握するのが難しくなります。

...ここでは、外側のループiでループカウンタi_1を作成する必要があります。

くそー! i_1は行ごとではなく列ごとです...


この状況はおなじみですか? uiRowCountとuiColCountのループを回避するのは難しくないので、そうしないことを望みます。 ただし、この場合、これらの変数の説明の意味は消えます。



自己文書化コードでは、多数の関数に分割する必要があるというステートメントがあります。 このコードは理解するのが難しく、実行速度が低下します。 古き良き履物を展開し、コメントで味付けし、トルストイの小説として読むことをお勧めします。



古い履物は非常に疑わしい喜びです。 読みやすさの問題ではなく、処理とエラー修正の容易さです。 さらに、因数分解されたコードは読みやすさの点で優れています。 機能-アルゴリズムの次の詳細レベル。 名前から、彼らが何をしているのかが明確になるはずです。 通常、アルゴリズムを詳細に検討する必要はありません。 また、ある点に興味がある場合は、関数の本体を見ることができます。 多くの関数は実行を遅くしますか? インラインを使用します。 同時に、100行以上の機能があり、読みやすさの問題はありません。



しかし、ライブラリはどうでしょうか?



間違いなく、ライブラリ関数のドキュメントを作成する必要があります。 ユーザーの観点からは、ドキュメントは別のファイルにある方が良いです。 なぜコード全体にもコメントするのですか? もちろんサディスティックな背景がない限り、すべてのニュアンスをライブラリの説明に含める必要があります。 「コードを見て、すべてがそこにあります」という説明でヒントに何度も出くわしました。実際には、これは、ライブラリを備えたRPMに加えて、ソースをダウンロードする必要があることを意味します。 関数を見つけて、ヘッダーとコード自体のコメントを読む必要があります。 次の機能についても同じです。 grep -Rはまだキャンセルされていません。



不快な状況でしょ? 同時に、別のファイルがバイナリとともに配布され、ユーザーは感謝のみを言います。 ところで、アーキテクチャまたはクラス階層の説明についても同じことが言えます。 複雑なチェーンがある場合、それらを別のファイルに記述してみませんか?



UPD
コミュニティのリクエストに応じて、サンプルコードを提供します。
 struct HGenStuff: public std::unary_function<const std::pair<wxString,int>&, void>{ std::map<wxString, DevDesc*>& mapDevs; std::map<wxString, LogDesc*>& mapLogs; HandlerLibData & hData; HGenStuff(std::map<wxString, DevDesc*>&_mapDevs, std::map<wxString, LogDesc*>&_mapLogs,HandlerLibData&_hData): mapDevs(_mapDevs), mapLogs(_mapLogs), hData(_hData) {}; inline void operator()(const std::pair<wxString,TypeFlag>&paInp){ if(paInp.second.isSet(HandlerLibData::DEVICE)){ std::map<std::string,DevInterface*>::iterator itDev; if((itDev = hData.HLI.mapDevs.find(std::string(paInp.first.mb_str())))!=hData.HLI.mapDevs.end()){ mapDevs.insert(std::make_pair(paInp.first, new DevDesc(itDev->second, &hData))); } } if(paInp.second.isSet(HandlerLibData::LOGGER)){ std::map<std::string,Logger *>::iterator itLog; if((itLog = hData.HLI.mapLogs.find(std::string(paInp.first.mb_str())))!=hData.HLI.mapLogs.end()){ mapLogs.insert(std::make_pair(paInp.first, new LogDesc(itLog->second, &hData))); } } } }; struct HandlerActivator: public std::unary_function<HandlerLibData&, void>{ HandlerBroker *pHB; std::map<wxString, DevDesc*>mapDevs; std::map<wxString, LogDesc*>mapLogs; std::map<wxString,std::map<wxString,TypeFlag> > &toUse; bool &bSuccess; HandlerActivator(HandlerBroker *_pHB, std::map<wxString,std::map<wxString,TypeFlag> > &_toUse, bool &_bSuccess):pHB(_pHB), toUse(_toUse), bSuccess(_bSuccess){ }; inline void operator()(HandlerLibData&inp){ std::map<wxString,std::map<wxString,TypeFlag> >::iterator it(toUse.find(inp.md5)); if(it != toUse.end()) std::for_each(it->second.begin(),it->second.end(),HGenStuff(mapDevs,mapLogs , inp)); } ~HandlerActivator(){ if (!pHB->checkLock(mapDevs)) bSuccess = wxYES == wxMessageBox(wxT("Some locks seam to be incompatible. Shall we use new device handlers selection?\n"),wxT("Confirm"), wxYES_NO | wxICON_EXCLAMATION ); if(bSuccess ) pHB->setAvailHandlers(mapDevs, mapLogs); }; }; bool MyFrame::pocessHandlers(std::map<wxString, std::map<wxString,TypeFlag> > &mapHandlersToUse){ std::set<HandlerLibData>::iterator it = strIntConf.setHandlerLibs.begin(); std::set<HandlerLibData>::iterator itEnd = strIntConf.setHandlerLibs.end(); bool bSuccess = true; HandlerActivator hGen(fGetHBroker(),mapHandlersToUse, bSuccess); while(it != itEnd) hGen(*const_cast<HandlerLibData*>(&(*it++))); return bSuccess; } void MyFrame::loadHandlers(){ wxDynamicLibrary dllDev; wxDir dirHandlers(strIntConf.sHandlersDir); wxString sLibName; if (!dirHandlers.GetFirst( &sLibName, wxEmptyString, wxDIR_FILES)) return; do { MD5 md5Op; wxString sFullPath = strIntConf.sHandlersDir + wxFileName::GetPathSeparator() +sLibName; wxString md5 = wxString(md5Op.digestFile((sFullPath).mb_str(wxConvLibc)),wxConvUTF8 ); if (strIntConf.setHandlerLibs.find(HandlerLibData(md5))!=strIntConf.setHandlerLibs.end()) continue; if(!dllDev.Load( sFullPath )) wxLogError(wxString::Format(wxT("Error Loading ")) + sLibName); else{ void (*dynLoad)(HandlerLibInterface *) = reinterpret_cast<void (*)(HandlerLibInterface* )>(dllDev.GetSymbol(wxT("dynLoad"))); if(dynLoad) { HandlerLibInterface HLI; dynLoad(&HLI); strIntConf.setHandlerLibs.insert( HandlerLibData( md5, sLibName, strIntConf.sHandlersDir, HLI,dllDev.Detach())); }else dllDev.Unload(); } }while(dirHandlers.GetNext( &sLibName)); }
      
      








All Articles