{"id":13,"date":"2018-07-31T10:00:00","date_gmt":"2018-07-31T10:00:00","guid":{"rendered":""},"modified":"2023-11-17T16:40:03","modified_gmt":"2023-11-17T16:40:03","slug":"lesson-learned-code-regression","status":"publish","type":"post","link":"https:\/\/ahm.basfinans.com\/index.php\/2018\/07\/31\/lesson-learned-code-regression\/","title":{"rendered":"Lesson Learned: Code Regression"},"content":{"rendered":"<div>\n<p><\/p>\n<div>\n<span><span style=\"color: black;\">Giving advice is not very effective most of the time. Sharing real experiences and trouble and how it is handled is more effective. The best is whoever learns from others mistakes. So I am sharing here a story where I and my team introduced a bug and it was leaked to the production environment. I know most of the advice&nbsp;here when I was consulting people in Agile but when the situation changed, I did that same mistake. The shame was painful and hence<\/span><\/span>&nbsp;the learning was intense. Experience is where you really learn, not advice from ivory towers.<\/div>\n<div>\n<span><span style=\"color: black;\"><br \/><\/span><\/span><\/div>\n<div>\n<span><span style=\"color: black;\">I am sharing here hoping that it will be useful for myself and for others.<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: black;\"><br \/><\/span><\/span><\/div>\n<div>\n<span><span style=\"color: black;\">Look at this code fragment that is a part of timezone based message broadcast.<\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp;&nbsp;<\/span>private String timezoneMetadataId = &#8220;23467fe6523310&#8221;;<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\">&nbsp; &nbsp; &nbsp; &nbsp;<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\">&nbsp; &nbsp; &nbsp; &nbsp;&#8230;<\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp;&nbsp; &nbsp; <\/span>\/\/Check Metadata for Timezone<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp; <\/span>List<metadatavalue> subTimezoneValue = sub.getSubscriberMetaData().get(timezoneMetadataId);<\/metadatavalue><\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp; <\/span>for (String timezone : timezones.split(&#8220;[;,]&#8221;)) {<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<\/span>for (MetadataValue mv : subTimezoneValue) {<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <\/span>\/\/Do some processing here<\/span><\/span><\/div>\n<div>\n<span style=\"color: blue;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<\/span>}<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp; <\/span>}<\/span><\/span><\/div>\n<div>\n<\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: black;\">The question here: Is timezoneMetadataId acceptable to be null? In our case, it must not be null.&nbsp;<\/span><\/span><span style=\"font-variant-ligatures: no-common-ligatures;\">The initialization above ensures it is not null.<\/span><\/div>\n<div>\n<\/div>\n<div>\n<span><span style=\"color: black;\">Until now, everything is ok, but the hardcoded timezoneMetadataId&nbsp;is not recommended especially as it is repeated in many places in the source code.<\/span><\/span><\/div>\n<div>\n<\/div>\n<div>\n<span><span style=\"color: black;\">We wanted to change this hardcoded id and place it inside the configuration file. As we use Guice dependency injection, we changed the above code to be:<\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<\/div>\n<div>\n<span><span style=\"color: black;\"><span>&nbsp;<span style=\"color: blue;\"> &nbsp; <\/span><\/span><span style=\"color: blue;\">@Named(value = &#8220;mongo.wmprod.subscriber.metadata.timezoneId&#8221;)<\/span><\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\"><span>&nbsp; &nbsp; <\/span>private String timezoneMetadataId;<\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<\/div>\n<div>\n<span><span style=\"color: black;\">And here we made the mistake of forgetting the <\/span><span style=\"color: blue;\">@Inject <\/span><span style=\"color: black;\">annotations which meant the @Named annotation has no effect and the variable, timezoneMetadataId is initiated to null. Sadly the above for loop code will not raise any errors as getting the value of key null is an empty list and looping over the empty list is ok.<\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: black;\">This is a code regression. The changes that intend to make the code better ended injected a critical bug.<\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\nWe have a&nbsp;Code Review process, the reviewer did not notice the mistake. Maybe because it was buried into a broad set of changed lines.&nbsp;<\/div>\n<div>\n<\/div>\n<div>\nQA also did their own testing, they did not run the timezone based broadcast test case.&nbsp;<\/div>\n<div>\n<\/div>\n<div>\nHere I am sharing lessons learned to avoid such regressions in the future:<\/div>\n<div>\n<\/div>\n<div>\n<\/div>\n<div>\n<span style=\"font-size: large;\">Lessons Learned for Programming:<\/span><\/div>\n<div>\n<\/div>\n<div>\nYou are changing the code. Do not be fooled by the simplicity of your changes or assume safety. Follow proven programming practices all the time.<\/div>\n<div>\n<\/div>\n<div>\n<span><span style=\"color: black;\"><b>1) Verify value is not null<\/b><\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span style=\"color: black;\">All configuration items must be verified. See below:<\/span><\/div>\n<div>\n<span style=\"color: black;\"><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\">import com.google.common.base.Preconditions;<\/span><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\">Preconditions.checkNotNull(timezoneMetadataId);<\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span style=\"color: black;\">You can also verify the size of the key or the validity of the key.&nbsp;<\/span><span style=\"font-variant-ligatures: no-common-ligatures;\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Fail-fast\" target=\"_blank\" rel=\"noopener\">Fail Fast<\/a> is your best friend.<\/span><\/div>\n<div>\n<\/div>\n<div>\n<span><span style=\"color: black;\"><b>2) Add log statement that shows the id.<\/b><\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: blue;\">logger.info(&#8220;Sending broadcast with timezone metadata id: {}&#8221;, timezoneMetadataId);<\/span><\/span><\/div>\n<div>\n<\/div>\n<div>\nIf the value is invalid in some way, you can check it in the log files.<\/div>\n<div>\n<span style=\"color: black;\"><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: black;\"><br \/><\/span><\/span><\/div>\n<div>\n<span><span style=\"color: black;\"><b>3) Write a unit test that ensures failure in case of null or invalid timezone metadata.<\/b><\/span><\/span><\/div>\n<div>\n<\/div>\n<div>\nActually, this will ensure that your preconditions are really working. It is indeed&nbsp;easy to make mistakes. Ensuring your preconditions and verifications are working is essential. If the project has no unit tests at all, create a task to create your first unit test immediately.&nbsp;<\/div>\n<div>\n<\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span><span style=\"color: black;\"><b>4) Write integration tests.&nbsp;<\/b><\/span><\/span><\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span style=\"color: black;\">In this project codebase, there was no integration testing framework in effect. If you join such team, create a task to create your first integration test in your first employment week.<\/span><\/div>\n<div>\n<span style=\"color: black;\"><br \/><\/span><br \/>\n<span style=\"color: black;\"><b>5) Use Constructor Injection<\/b><\/span><br \/>\n<span style=\"color: black;\">See&nbsp;https:\/\/github.com\/google\/guice\/wiki\/Injections<\/span><\/div>\n<div>\n<\/div>\n<div>\n<span style=\"font-size: large;\">Lessons Learned for Code Review:<\/span><\/div>\n<div>\n<\/div>\n<div>\n<span style=\"color: black;\"><span><\/span><br \/><\/span><\/div>\n<div>\n<span style=\"color: black;\">We did not have a written checklist for code review. This is a mistake. Even if you join a team that does not have a checklist,&nbsp;do not wait until you have team experiences to create your own list. Conduct a meeting and start with a simple checklist immediately. With each Story or Bug Code Review, the checklist should be filled and attached to the Story or Bug. The checklist template should be updated frequently.<\/span><\/div>\n<div>\n<span style=\"color: black;\"><br \/><\/span><\/div>\n<div>\n<span style=\"color: black;\">We took Code Review seriously but with no structure. The above ideas are to make it serious process with explicit checks and responsibility.&nbsp;<\/span><\/div>\n<div>\n<span style=\"color: black;\"><br \/><\/span><\/div>\n<div>\n<span style=\"font-size: large;\">Lessons Learned for QA:<\/span><\/div>\n<div>\n<span style=\"font-size: large;\"><br \/><\/span><\/div>\n<div>\n<span style=\"color: black;\">We kept assuring the safety of changes to Project Leader and QA. This is really a mistake. Fears should be reduced by adding more test cases not by getting developers assurance about the safety of the changes.<\/span><\/div>\n<div>\n<span style=\"color: black;\"><br \/><\/span><\/div>\n<div>\n<span style=\"color: black;\">I find it necessary to list all changed functionality to QA. It is even better for QA to have access to changes themselves. Once QA read source code nouns such as variables names, functions names, and class names, they can associate it to UI functionality and create the corresponding test cases.<\/span><\/div>\n<div>\n<\/div>\n<div>\n<\/div>\n<div>\nIn the end, I hope my mistakes and lessons learned will be useful.<span style=\"color: black;\"><span><\/span><\/span><\/div>\n<div>\n<span><\/span><\/div>\n<div>\n<\/div>\n<\/div>\n<div>From ahm507.blogspot.com<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Giving advice is not very effective most of the time. Sharing real experiences and trouble and how it is handled is more effective. The best is whoever learns from others mistakes. So I am sharing here a story where I and my team introduced a bug and it was leaked to the production environment. I [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/posts\/13"}],"collection":[{"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/comments?post=13"}],"version-history":[{"count":1,"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/posts\/13\/revisions"}],"predecessor-version":[{"id":251,"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/posts\/13\/revisions\/251"}],"wp:attachment":[{"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/media?parent=13"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/categories?post=13"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ahm.basfinans.com\/index.php\/wp-json\/wp\/v2\/tags?post=13"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}