The source of all technical debt

The source of all technical debt

Indebted code is any code that is hard to scan. Technical debt is anything that increases the difficulty of reading code. As software engineers we spend most of the time reading code, and our job is to understand it and modify it in order to do more things with it. If we can’t understand the code, or we can’t even find it, the amount of technical debt accumulated will be over the roof.

820df515de752bffa0ce2644a7927186?s=128

David González

March 22, 2017
Tweet

Transcript

  1. The source of all technical debt

  2. Indebted code is any code that is hard to scan.

    Technical debt is anything that increases the difficulty of reading code.
  3. Programmers spend around 60-70% of their entire programming time reading

    code. Completely made up number based on my last month
  4. Cyclomatic complexity Software metric (measurement), used to indicate the complexity

    of a program. It is a quantitative measure of the number of linearly independent paths through a program's source code.
  5. Reducing technical debt Look at something Have an insight Write

    it down Check it in
  6. Reducing technical debt Have an insight

  7. Reducing technical debt Decide where to look Reading things, usually

    names In a name or assertion Name your commit
  8. 7 stages of naming

  9. Nonsense preloadDetails();

  10. Honest doSomethingEvilToTheDatabaseAndDisplayTheResult();

  11. Not just for functions public class DataManager public class DataProvider

    public class DataRepository public class DataOperations
  12. Honest and Complete parseXmlAndStoreFlightToDatabaseAndLocalCacheAndBeginBackgroundProcessing();

  13. None
  14. Does the right thing storeFlightToDatabaseAndStartProcessing();

  15. Intent beginTrackingFlight();

  16. Domain abstraction MonitoringPanel.add(new Flight());

  17. Define your language

  18. De!ne your language presenter.loadFolders(); presenter.getFolders(); presenter.fetchFolders(); view.presentFolders(); view.showFolders(); view.renderFolders();

  19. De!ne your language

  20. De!ne your language view.showFolders(boolean isOnline); presenter.loadFolders(boolean fromCache);

  21. De!ne your language presenter.loadFolders(boolean fromCache); view.showFolders(); view.notifyOffline();

  22. Name by what it does, not by what it is

    @BindView(R.id.password_text_input_layout) TextInputLayout passwordTextInputLayout; @BindView(R.id.password_edit_text) EditText etPassword; @BindView(R.id.password) EditText passwordInput;
  23. Just say mNo to Hungarian Notation http://jakewharton.com/just-say-no-to-hungarian-notation/

  24. Say mNo to hungarian notation

  25. Your strict naming conventions are a liability https://publicobject.com/2016/01/20/strict-naming-conventions-are-a-liability/

  26. Rest API don’t de!ne your language { "files": { "Hello.txt":

    { "type": "text/plain", "content": "Hello World!\n" } }, "created_at": "2014-05-27T02:31:35Z", "updated_at": "2015-08-29T14:01:51Z" }
  27. Rest API don’t de!ne your language public final class Gist

    { Map<String, GistFile> files; @SerializedName("created_at") Date createdAt; @SerializedName("updated_at") Date updatedAt; }
  28. Let’s talk about testing

  29. Naming your tests @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() DraftDialogPresenter.java

  30. Naming your tests DraftDialogPresenter.java @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData()

  31. Naming your tests @Test public void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() DraftDialogPresenter.java @Test public

    void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData()
  32. Naming your tests DraftDialogPresenter.java @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public

    void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData()
  33. Naming your tests DraftDialogPresenter.java @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public

    void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData()
  34. Naming your tests DraftDialogPresenter.java @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public

    void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData()
  35. Naming your tests DraftDialogPresenter.java @Test public void showsMessageWhenDraftIsSaved() @Test public

    void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData()
  36. Naming your tests DraftDialogPresenter.java @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public

    void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public void showsMessageWhenDraftIsSaved()
  37. Naming your tests DraftDialogPresenter.java @Test public void showsSuccessMessageWhenDraftIsSaved() @Test public

    void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public void showsMessageWhenDraftIsSaved()
  38. Naming your tests DraftDialogPresenter.java @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public

    void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public void showsMessageWhenDraftIsSaved() @Test public void showsSuccessMessageWhenDraftIsSaved()
  39. Naming your tests DraftDialogPresenter.java @Test public void showsErrorMessageWhenDraftIsNotSaved() @Test public

    void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public void showsMessageWhenDraftIsSaved() @Test public void showsSuccessMessageWhenDraftIsSaved()
  40. Naming your tests DraftDialogPresenter.java @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public

    void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public void showsMessageWhenDraftIsSaved() @Test public void showsSuccessMessageWhenDraftIsSaved() @Test public void showsErrorMessageWhenDraftIsNotSaved()
  41. Naming your tests DraftDialogPresenter.java @Test public void shows_error_mesage_when_draft_is_not_saved() @Test public

    void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public void showsMessageWhenDraftIsSaved() @Test public void showsSuccessMessageWhenDraftIsSaved() @Test public void showsErrorMessageWhenDraftIsNotSaved()
  42. Naming your tests DraftDialogPresenter.java @Test public void testDraftDialogPresenterShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public

    void draftDialogShowsMessageAfterClickingSaveButtonAndReloadsData() @Test public void showsMessageWhenDraftIsSavedAndReloadsData() @Test public void showsMessageWhenDraftIsSaved() @Test public void showsSuccessMessageWhenDraftIsSaved() @Test public void showsErrorMessageWhenDraftIsNotSaved() @Test public void shows_error_mesage_when_draft_is_not_saved()
  43. Naming your tests DraftDialogPresenter.java // Groovy def "Should show success

    message after successfully saved a draft"() // Kotlin fun `Should show success message after successfully saved a draft`()
  44. Naming your tests @Test public void showsErrorMessageWhenDraftIsNotSaved() {} @Test public

    void shows_error_mesage_when_draft_is_not_saved() {} // Groovy def "Should show success message after successfully saved a draft"() // Kotlin fun `Should show success message after successfully saved a draft`()
  45. Android package structure

  46. None
  47. helpscout api app database

  48. app common data domain injection

  49. domain conversations folders mailboxes session search settings

  50. mailboxes model usecases view MailboxesMVP MailboxesPresenter

  51. Android resource management

  52. Styles

  53. Styles <TextView android:id="@+id/conversations_list_subject_name" style="@style/Widget.Subject.Pending" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="Customer Name" /> view-convo-preview.xml

  54. Styles <style name="Widget.Subject" parent="TextAppearance.AppCompat.Body1"> <item name="android:textSize">@dimen/convo_subject_text</item> <item name="android:ellipsize">end</item> <item name="android:maxLines">1</item>

    </style> <style name="Widget.Subject.Pending"> <item name="android:textColor">@color/convo_preview_pending</item> </style> convo-preview-styles.xml
  55. Colors <style name="Widget.Subject.Pending"> <item name="android:textColor">@color/convo_preview_pending</item> </style> convo-preview-styles.xml <color name="convo_preview_pending">@color/charcoal_300</color> convo-preview-colors.xml

    <color name="charcoal_300">#72808e</color> colors.xml
  56. Dimensions <style name="Widget.PreviewText" parent="TextAppearance.AppCompat.Body1"> <item name="android:textSize">@dimen/convo_preview_text</item> <item name="android:ellipsize">end</item> <item name="android:maxLines">1</item>

    </style> convo-preview-styles.xml <dimen name="conversation_preview_text">@dimen/text_subhead</color> convo-preview-dimens.xml <dimen name="text_subhead">11sp</dimen> dimens.xml
  57. Strings <?xml version="1.0" encoding="utf-8"?> <resources> <string name="convo_preview_archived">@string/convo_archived</string> <string name="convo_preview_restored">@string/convo_restored</string> </resources>

    convo-preview-strings.xml <string name="conversation_archived">Conversation archived.</string> <string name="conversation_restored">Conversation status restored.</string> strings-translatable.xml
  58. None
  59. Files

  60. We are talking about conventions and we should share them

    with the team
  61. https://google.github.io/styleguide/javaguide.html#s5.1-identifier-names

  62. http://s.android.com/source/code-style.html#follow-field-naming-conventions

  63. None
  64. None
  65. Enforce those conventions

  66. Enforce conventions

  67. Enforce conventions <code_scheme name="Novoda"> ... <option name="RIGHT_MARGIN" value="150" /> ...

    <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="2" /> <option name="TAB_SIZE" value="2" /> </indentOptions> ... </code_scheme>
  68. Enforce conventions <module name="ConstantNameCheck"> <metadata name="altname" value="ConstantName" /> <property name="applyToPublic"

    value="true" /> <property name="applyToProtected" value="true" /> <property name="applyToPackage" value="true" /> <property name="applyToPrivate" value="false" /> <property name="format" value="^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$" /> <message key="name.invalidPattern" value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)." /> <property name="severity" value="warning" /> </module> team-props/checkstyle/modules.xml <module name="MethodNameCheck"> <metadata name="altname" value="MethodName" /> <property name="format" value="^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$" /> <property name="severity" value="warning" /> </module>
  69. Enforce conventions <rule ref="rulesets/java/design.xml"> <exclude name="TooFewBranchesForASwitchStatement" /> <exclude name="ConfusingTernary" />

    <!-- we frequently do this on purpose when connecting to the Android life-cycle --> <exclude name="UncommentedEmptyMethod" /> <!-- we do this for Dagger --> <exclude name="UncommentedEmptyConstructor" /> <exclude name="UseVarargs" /> <!-- we always create singletons for this classes and doing this would not allow mocking --> <exclude name="ClassWithOnlyPrivateConstructorsShouldBeFinal" /> <exclude name="NonThreadSafeSingleton" /> </rule> team-props/pmd/ruleset.xml
  70. Enforce conventions static-analysis.gradle apply plugin: 'checkstyle' def rulesDir = new

    File(project.teamPropsDir, 'rules') task checkstyleMain(type: Checkstyle) { description 'Checks whether Java source code complies with coding rules.' ... } staticAnalysis.dependsOn checkstyleMain task verifyNoCheckstyleWarnings { doLast { File warningsFile = file('buildMessage/reports/checkstyle/main.xml') if (warningsFile.exists() && warningsFile.text.contains("<error ")) { throw new GradleException("There were checkstyle warnings! For more info check $warningsFile") } } }
  71. Enforce conventions static-analysis.gradle apply plugin: 'findbugs' task findbugsMain(type: FindBugs) {

    description 'Uses static analysis to look for bugs in Java code.' ... } staticAnalysis.dependsOn findbugsMain apply plugin: 'pmd' task pmdMain(type: Pmd) { description 'Finds common programming flaws throw static analysis of code.' } staticAnalysis.dependsOn pmdMain check.dependsOn staticAnalysis
  72. Static analysis

  73. Good naming is a process, not a single step -

    http://arlobelshee.com/good-naming-is-a-process-not-a-single-step/ 1 Resources Just say hNo to hungarian notation - http://jakewharton.com/just-say-no-to-hungarian-notation/ How We Rethought our Complete Package Structure for Buffer on Android and the Awesome Effect It’s Had on Our Workflows - https://overflow.buffer.com/2016/09/26/android-rethinking-package-structure/ Share the settings with the whole team - https://tips.seebrock3r.me/share-settings-with-the-team-a-year-later- e28c24fc07aa#.sihndb3f3
  74. Novoda IDE Settings - https://github.com/novoda/novoda/tree/master/ide-settings 1 Resources Buffer’s Android Guidelines

    - https://github.com/bufferapp/android-guidelines Vincent Brison’s Static Analysis with Gradle - https://github.com/vincentbrison/vb-android-app-quality
  75. Questions? David González @dggonzalez malmstein@gmail.com