Loading...

メンテナンスしやすいコードとは何だろうか?

f:id:nasust:20170625154320j:plain


こんにちはnasustです。

プログラマの仕事をしていると、自分的に多いのがゼロからの開発ではなくて、 途中参加して、機能を追加することが多いです。

そして個人的にアプリや小規模のWebサービスの開発に関わる事が多いです

この時困るのが、コメントやドキュメントが無い場合が多いです。

こういう仕事の場合、コードが理解しやすいかで仕事の難易度が決まることです。

個人的には、コメントやドキュメントが無くても構わないです。コメントやドキュメントは、 度重なるバージョンアップでロジックの実態を表していない場合があるので、有ろうが無かろうが、 コードを理解する為にどのみち読んだりしますので重要視していないです。

しかし、コード自体がスパゲティであると、とても理解するのに困難になります。

ゼロからの開発に関わっている開発者であれば、理解しているかもしれません。 しかし、途中参加であれば理解するのが困難なので、機能を追加するのが大変です。

では理解しやすいコードとは

全てがシンプルで、一貫性のあるコードです。

文章で表現し辛いですが、理解しにくいコードというのは迷路のようです。 くねくね曲がり食って、街の未計画的な道路のように目的地に付くまでの道順が分からないようなものです。

逆に分かりやすいコードは、答えまでの目的地までの道順が分かりやすい事です。道の曲がる回数も少なく、 分かりやすい場所で曲がる為にたどり着きやすい、そんな感じです。

この辺の理解出来やすいかは、UIの設計に似ていると思います。分かりにくいUIは、目的の機能まで辿り着くのが大変ですが、 優れているものは、簡単に操作できます。

メンテナンスしやすいコードとは

一貫性を持たせるの一言です。ですが様々な開発者が作業する為に一貫性を保つのが大変です。 コーディングルールというレベルでは無くて、構造の設計の仕方などの問題です。

現在の開発は大抵オブジェクト指向ですが、クラス設計の良し悪しが強く属人的な為に一貫性が保ちにくいです。

僕が出会った最悪のクラス設計した開発者は、派生クラスを作る度に、親のクラスに派生クラスの共通コードを追加していた事です。 クラスの抽象化という概念が抜けています。これでは派生クラスをメンテナンスする度に、親クラスのメンテナンスが必要になります。

素晴らしい開発者は、こういう間違ったクラス設計はしないと思います。しかし実際の現場では、出来る人できない開発者が混じり合って開発していきます。

これらを防ぐために、ペアプログラミングなどしますが小規模ですと実施も難しいです。コードレビューも適切に指摘する人がいなければ、ぐだぐだです。

では、こういう構造的問題が出やすい環境でメンテナンスしやすいコードにするには、オブジェクト指向を止めるという選択肢もありだと思っています。

オブジェクト指向のクラスの抽象化という作業は、属人的すぎるので品質を保てないと思います。 その代わり、プロトコル指向で開発することで品質を保ちやすいじゃないかと思っています。

オブジェクト指向は素晴らしいですが、実務に関しては人類には早すぎた概念かもしれません。誰もが使いこなせるとは思えないです。 クラスの抽象化という作業は、自分の頭で想像出来ていても、第三者にはとても理解しにくいです。また抽象化が適切であるのかという議論も泥沼化しやすいです。

クラスはシンプルに機能の塊にします。

プロトコル指向では関数の設計だけなので誰でもある程度の品質のものが出来きて、第三者でも評価しやすいと思います。

現実の機械や電子部品などは、規格が決まっている為に、様々な会社が同じような部品を開発しても、同じように動作する事が出来ます。 プロトコル指向では、インターフェイスの規格を決めることが出来るので、コードの構造をある程度一貫性を決められる事が出来るため、メンテナンスしやすいです。 また、常に分かりやすいようにソースコードリファクタリングしていれば、メンテナンスしやすいです。

最後に

だれか凄い人が、誰もが理解しやすいプログラム言語を作って欲しいです。色々妄想で考えるですが、妄想すら到れないです。

自分が欲しい機能のコードが勝手に出来上がる未来が欲しい。

" item.append(html); } }) }) }); //関連記事にはてなスター追加 $(function() { var items = $(".relatedArticleListItem"); var urlList = []; items.each(function() { var item = $(this); var link = item.find(".relatedArticleListItemImage a"); var href = link.attr("href"); urlList.push(encodeURIComponent(href)) }); url = "https://nasust.com/fcgi/star?urls=" url += urlList.join(",") url += "&callback=?" $.getJSON(url, function(json) { items.each(function() { var item = $(this); var link = item.find(".relatedArticleListItemImage a"); var href = link.attr("href"); var starCount = json[href]; if (starCount > 0) { var html = "
" + starCount + "
"; item.append(html); } }) }); })

おすすめ記事

") }); })(); (function() { //ぼけ画像の背景と画像の平均色を背景に設定 var archiveEntry = $(".archive-entry:first"); //googleのスクリプトを削除 $(".entry-description").each(function() { var ed = $(this); var description = ed.text(); description = description.replace("(adsbygoogle = window.adsbygoogle || []).push({});", "") ed.text(description); }); //続きを読むを追加 $(".archive-entry").each(function() { var archiveEntry = $(this) var entryTitleLink = archiveEntry.find(".entry-title-link"); var href = entryTitleLink.attr("href") var entryTitleLink = archiveEntry.find(".entry-description"); var html = "続きを読む
"; entryTitleLink.after(html); }); if (!md.mobile()) { (function() { //サイトマップを移動 var sitemap = $("#sitemap"); var entry = $(".entry"); if (entry.length === 1) { entry.after(sitemap); } else { var mainInner = $("#main-inner"); mainInner.append(sitemap); } }()); } }()); (function(config) { var categoriesRule = []; config.categories.forEach(function(configCategoryRuleRow) { var categoriesRuleRow = []; configCategoryRuleRow.forEach(function(configCategoryRuleCol) { var rule = { title: undefined, priority: 0, url: undefined }; if ($.isArray(configCategoryRuleCol)) { rule.title = configCategoryRuleCol[0]; if (configCategoryRuleCol.length >= 1) { rule.url = configCategoryRuleCol[1]; } } else { rule.title = configCategoryRuleCol; } categoriesRuleRow.push(rule) }); var key = categoriesRuleRow[categoriesRuleRow.length - 1].title; categoriesRule[key] = categoriesRuleRow; }); var moreRelatedArticleRender = function() { var categoryLink = $(".entry-categories a:first"); if (categoryLink.length > 0) { var href = categoryLink.attr("href"); relatedArticle = $(".relatedArticle"); if (relatedArticle.length > 0) { html = "
"; html += "関連記事をもっと読む"; html += "
"; // html += "
" relatedArticle.after(html); } } } var renderCategoryTree = function(ruleRow) { var html = "" if (!md.mobile() || md.tablet()) { $(".entry-header").append(html); } else { var eyecache = $(".eyecache"); if (eyecache.length > 0) { eyecache.after("
" + html + "
"); } else { $(".entry-header").append(html); } } moreRelatedArticleRender(); $(".entry-categories").remove(); //$( "
" + html + "
").appendTo(".entry-content"); //$(".entry-contet-footer").append( html ); } $(".entry-categories").each(function() { var categories = $(this); var hitRuleList = []; var categorylinks = categories.children(); categorylinks.each(function() { var categoryLink = $(this); var cunnretHitRule = categoriesRule[categoryLink.text()]; if (cunnretHitRule) { var updateIndex = -1; hitRuleList.forEach(function(hitRule, index) { if (hitRule.length < cunnretHitRule.length) { var hit = true; for (var i = 0; i < hitRule.length; i++) { var hitRuleTitle = hitRule[i].title; var cunnretHitRuleTitle = cunnretHitRule[i].title; if (hitRuleTitle !== cunnretHitRuleTitle) { hit = false; } } if (hit) { updateIndex = index; } } else if (hitRule.length > cunnretHitRule.length) { var hit = true; for (var i = 0; i < cunnretHitRule.length; i++) { var hitRuleTitle = hitRule[i].title; var cunnretHitRuleTitle = cunnretHitRule[i].title; if (hitRuleTitle !== cunnretHitRuleTitle) { hit = false; } } if (hit) { updateIndex = -2; } } }); if (updateIndex == -1) { hitRuleList.push(cunnretHitRule) } else if (updateIndex == -2) { //ignore } else { hitRuleList[updateIndex] = cunnretHitRule; } } }) if (hitRuleList.length > 0) { hitRuleList.forEach(function(hitRule) { renderCategoryTree(hitRule); }); } else { var categoryRuleRow = []; categorylinks.each(function() { var categoryLink = $(this); categoryRuleRow.push({ title: categoryLink.text(), priority: 0, url: undefined }); }); renderCategoryTree(categoryRuleRow); } }) })({ top: "/archive", categoryURLPrefix: "/archive/category/", categories: [ ["雑記", "社会"], ["雑記", "IT色々"], ["雑記", "Spotify"], ["はてなブログカスタマイズ"], ["プログラミング"], ["プログラミング", "WEB開発"], ["プログラミング", ["Go言語 / golang", "/entry/golang"]], ["プログラミング", ["Go言語 / golang", "/entry/golang"], ["Go言語入門 / golang 入門", "/entry/2016/11/17/002020"] ], ["プログラミング", "Swift", "Swift入門"], [ ["WEBデザイン入門", "/entry/webdesign"], "ブロガー向けのCSS入門" ], [ ["人力まとめ", "/entry/newscuration"], "はてなブログ村のまとめ" ], [ ["人力まとめ", "/entry/newscuration"], "UI/UX/Webデザインのまとめ" ], [ ["人力まとめ", "/entry/newscuration"], "プログラミングのまとめ" ], [ ["人力まとめ", "/entry/newscuration"], "ライフハック・労働のまとめ" ] ] }); (function(config) { if (!$('body').hasClass('page-archive')) { return; } if (location.pathname != "/archive") { return; } $(".archive-entry").each(function() { var archiveEntry = $(this); var archiveCategoryLinkResult = archiveEntry.find(".archive-category-link"); archiveCategoryLinkResult.each(function() { var archiveCategoryLink = $(this); if (config.indexOf(archiveCategoryLink.text()) >= 0) { archiveEntry.remove(); return false; } }) }); }(["ビジネス・金融・マーケットのまとめ", "政治・社会のまとめ", "プログラミングのまとめ", "Apple・Mac・iPhone・iPadのまとめ", "はてなブログ村のまとめ", "ライフハック・労働のまとめ", "色々なブックマークまとめ", "UI/UX/Webデザインのまとめ" ])); //はてブ数追加 (function() { var hrefList = []; var archiveEntries = $(".archive-entry"); archiveEntries.each(function() { var archiveEntry = $(this) var entryTitleLink = archiveEntry.find(".entry-title-link"); var href = entryTitleLink.attr("href") hrefList.push(href); }) if (hrefList.length === 0) { return; } var uris = "" for (var i = 0; i < hrefList.length; i++) { uris += "url=" + encodeURIComponent(hrefList[i]) + "&" } $.getJSON("http://api.b.st-hatena.com/entry.counts?" + uris + "callback=?", function(json) { archiveEntries.each(function() { var archiveEntry = $(this) var entryTitleLink = archiveEntry.find(".entry-title-link"); var href = entryTitleLink.attr("href") var count = json[href]; if (count > 0) { var html = "
" if (count < 10) { html += "" } else { html += "" } html += "" html += count; html += "" html += " bookmarks"; html += "" html += "
" entryTitleLink.before(html); } }); }); }()); //スター数追加 (function() { var urlList = []; var archiveEntries = $(".archive-entry"); archiveEntries.each(function() { var archiveEntry = $(this) var entryTitleLink = archiveEntry.find(".entry-title-link"); var href = entryTitleLink.attr("href") urlList.push(encodeURIComponent(href)); }) if (urlList.length === 0) { return; } url = "https://nasust.com/fcgi/star?urls=" url += urlList.join(",") url += "&callback=?" $.getJSON(url, function(json) { archiveEntries.each(function() { var archiveEntry = $(this); var entryTitleLink = archiveEntry.find(".entry-title-link"); var href = entryTitleLink.attr("href"); var count = json[href]; if (count > 0) { var html = "
" + count + "
"; entryTitleLink.before(html); } }); }); }()); $(window).load(function() { var addHatenaStar = function(moduleName) { var urlListItems = $(moduleName).find(".urllist-item-inner"); if (urlListItems.length == 0) { return; } var urlList = []; urlListItems.each(function() { var urlListItem = $(this); var link = urlListItem.find(".urllist-title-link"); var href = link.attr("href"); urlList.push(encodeURIComponent(href)); }); url = "https://nasust.com/fcgi/star?urls=" url += urlList.join(",") url += "&callback=?" $.getJSON(url, function(json) { urlListItems.each(function() { var urlListItem = $(this); var link = urlListItem.find(".urllist-title-link"); var href = link.attr("href"); var starCount = json[href]; if (starCount > 0) { var html = "
" + starCount + "
"; urlListItem.append(html); } }); }); } addHatenaStar(".hatena-module-entries-access-ranking"); addHatenaStar(".hatena-module-recent-entries"); addHatenaStar(".hatena-module-related-entries"); });