managing technical debt in django web...

49
IN DEGREE PROJECT COMPUTER SCIENCE AND ENGINEERING, SECOND CYCLE, 30 CREDITS , STOCKHOLM SWEDEN 2016 Managing Technical Debt in Django Web Applications PER CLASSON KTH ROYAL INSTITUTE OF TECHNOLOGY SCHOOL OF COMPUTER SCIENCE AND COMMUNICATION

Upload: others

Post on 14-May-2020

12 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

IN DEGREE PROJECT COMPUTER SCIENCE AND ENGINEERING, SECOND CYCLE, 30 CREDITS

, STOCKHOLM SWEDEN 2016

Managing Technical Debt in Django Web Applications

PER CLASSON

KTH ROYAL INSTITUTE OF TECHNOLOGYSCHOOL OF COMPUTER SCIENCE AND COMMUNICATION

Page 2: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Managing Technical Debtin Django Web Applications

PER [email protected]

2016-03-12

Master’s Thesis at CSCSupervisor: Karl MeinkeExaminer: Johan Håstad

Page 3: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE
Page 4: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Abstract

Technical debt is a metaphor that refers to the consequencesof suboptimal software development. Developers will haveto pay interest on this debt, in terms of costs of mainte-nance. The term helps developers communicate the impor-tance of software quality. This thesis has studied technicaldebt in the context of Django web applications.

In a survey conducted, the main causes of technicaldebt in Django applications were found to be architecturalissues and lack of testing. This is in line with other studiesof causes of technical debt. Tools and practices used inDjango development were evaluated. From this evaluationseveral guidelines were formulated on how to best manageand limit technical debt. The results suggest that staticcode analyzers should be used to maintain code standards.Furthermore, the evaluation show that log aggregation toolslike Sentry are helpful. Application monitoring should beused if there are performance issues, deprecation patternscan be used in refactorizations and the identification andremoval of dead code is probably unnecessary. Finally, pre-commit tools help in preventing technical debt.

Page 5: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Referat

Hantering utav teknisk skuld i Djangowebbapplikationer

Teknisk skuld är en metafor som beskriver konsekven-serna utav suboptimal mjukvaruutveckling. Utvecklare mås-te betala ränta på denna skuld, i form utav kostnader förunderhåll. Termen hjälper utvecklare att kommunicera vik-ten utav programvarukvalitet. Denna rapport har studeratteknisk skuld i kontexten utav Django webbapplikationer.

En enkätundersökning gjordes och de främsta orsaker-na till teknisk skuld i Django applikationer visade sig varaarkitektoniska problem och brist utav testning. Detta liggeri linje med andra studier utav orsakerna av teknisk skuld.Verktyg och metoder som används i Django utveckling ut-värderades. Från denna utvärdering flera riktlinjer formu-lerades om hur man bäst hanterar och begränsar tekniskskuld. Resultaten visar på att statisk programanalys böranvändas för att upprätthålla kod standarder. Dessutom vi-sar utvärderingen att log aggregerings verktyg som Sentryär användbara. Applikations övervakning bör användas omdet finns prestandaproblem, deprecation patterns kan an-vändas i refaktoriseringar och identifiering av död kod ärförmodligen onödigt. Slutligen visar sig pre-commit verk-tyg vara hjälpsamma i att förebygga teknisk skuld.

Page 6: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Contents

1 Introduction 1

1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Research questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.3 Scope and limitations . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Background and Literature Study 3

2.1 The technical debt metaphor . . . . . . . . . . . . . . . . . . . . . . 32.1.1 Technical debt quadrant . . . . . . . . . . . . . . . . . . . . . 42.1.2 Managing technical debt research . . . . . . . . . . . . . . . . 42.1.3 Types of technical debt . . . . . . . . . . . . . . . . . . . . . 5

2.2 Causes of technical debt . . . . . . . . . . . . . . . . . . . . . . . . . 62.2.1 Architectural issues . . . . . . . . . . . . . . . . . . . . . . . 62.2.2 Lack of adhering to coding style and conventions . . . . . . . 72.2.3 Code duplication . . . . . . . . . . . . . . . . . . . . . . . . . 72.2.4 Dead and obsolete code . . . . . . . . . . . . . . . . . . . . . 72.2.5 Overly complex code . . . . . . . . . . . . . . . . . . . . . . . 72.2.6 Legacy software package dependencies . . . . . . . . . . . . . 82.2.7 Lack of testing . . . . . . . . . . . . . . . . . . . . . . . . . . 82.2.8 Poor tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.2.9 Lack of or outdated documentation . . . . . . . . . . . . . . . 8

2.3 Python and Django applications . . . . . . . . . . . . . . . . . . . . 92.4 Django-specific causes of technical debt . . . . . . . . . . . . . . . . 9

2.4.1 Monolithic Django apps . . . . . . . . . . . . . . . . . . . . . 92.4.2 Misuse of signal receivers . . . . . . . . . . . . . . . . . . . . 92.4.3 Overuse of middleware and context processors . . . . . . . . 102.4.4 Heavy queries from Django ORM . . . . . . . . . . . . . . . . 112.4.5 Django models become god objects . . . . . . . . . . . . . . . 122.4.6 Complex template hierarchies . . . . . . . . . . . . . . . . . . 12

2.5 Technical debt management . . . . . . . . . . . . . . . . . . . . . . . 13

3 Method 15

3.1 Survey on technical debt . . . . . . . . . . . . . . . . . . . . . . . . . 153.2 Case study of managing technical debt . . . . . . . . . . . . . . . . . 16

Page 7: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

3.2.1 Test code base . . . . . . . . . . . . . . . . . . . . . . . . . . 163.2.2 Evaluation criteria . . . . . . . . . . . . . . . . . . . . . . . . 16

4 Results 17

4.1 Survey responses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174.1.1 Demographic information . . . . . . . . . . . . . . . . . . . . 174.1.2 Cause of technical debt . . . . . . . . . . . . . . . . . . . . . 18

4.2 Evaluations of tools and practices identifying technical debt . . . . . 194.3 Logging aggregators . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

4.3.1 Sentry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204.3.2 ElasticSearch, Logstash and Kibana . . . . . . . . . . . . . . 21

4.4 Application monitoring . . . . . . . . . . . . . . . . . . . . . . . . . . 224.4.1 New Relic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.4.2 AppEnlight . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

4.5 Static code analyzers . . . . . . . . . . . . . . . . . . . . . . . . . . . 244.5.1 pep8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244.5.2 Pyflakes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254.5.3 Flake8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254.5.4 PyLint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264.5.5 Vulture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

4.6 Evaluations of tools and practices to repay technical debt . . . . . . 264.6.1 Tombstone decorators . . . . . . . . . . . . . . . . . . . . . . 264.6.2 Automated code formatting . . . . . . . . . . . . . . . . . . . 27

4.7 Evaluations of tools and practices to prevent technical debt . . . . . 284.7.1 Pre-commit hooks . . . . . . . . . . . . . . . . . . . . . . . . 284.7.2 Deprecation decorators . . . . . . . . . . . . . . . . . . . . . 28

5 Discussion 31

5.1 Interpretation of survey results . . . . . . . . . . . . . . . . . . . . . 315.1.1 Familiarity with technical debt . . . . . . . . . . . . . . . . . 315.1.2 Causes of technical debt . . . . . . . . . . . . . . . . . . . . . 315.1.3 Definition of technical debt . . . . . . . . . . . . . . . . . . . 32

5.2 Guidelines when developing with Django to manage technical debt . 325.2.1 Follow code standards with help of static code analyzers . . . 325.2.2 Use Sentry to aggregate logs . . . . . . . . . . . . . . . . . . 335.2.3 If there are performance issues use application monitoring . . 335.2.4 Deprecate functions with Python decorators . . . . . . . . . . 335.2.5 Prevent technical debt with pre-commit tools . . . . . . . . . 335.2.6 Active identification of dead code might be unnecessary . . . 34

5.3 Reliability of the results . . . . . . . . . . . . . . . . . . . . . . . . . 34

6 Conclusions 35

6.1 Future work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

Page 8: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Bibliography 37

Page 9: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE
Page 10: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Chapter 1

Introduction

The technical debt metaphor refers to the consequences of sub-optimal softwaredevelopment [3]. Examples of technical debt could be architectural issues or unusedcode. For any system that has technical debt, developers will have to pay intereston this debt in terms of costs of maintenance. By making technical debt visible, andeventually repaying it (for example by re-factorization), developers can make surethat the debt make as little harm as possible. The term technical debt is useful fordevelopers when discussing and communicating the importance of software quality.

Technical debt exists in all types of software, but it is di�erent depending onwhat kind of framework or programming language that is used. The most popularweb framework for Python is the free and open source Django framework. It is afull-stack web framework that makes it easy to develop complex, database-drivenweb applications. To keep such applications maintainable, it is important to managetheir technical debt; and that is the topic of this thesis.

1.1 MotivationThere have been a lot of research done on technical debt and its management. Theaim of the research has been to improve current software techniques, to increasesoftware development productivity.

The technical debt metaphor can have many interpretations, depending on pro-gramming language, framework choice, or hardware dependencies. There have beena lack of field studies, therefore it is useful to investigate causes of technical debtin the context of Django web applications. In this thesis it is done by conductinga survey. This does not only help to further define the metaphor, but can alsohelp out in management of technical debt in Django, as the causes of debt can beidentified easier.

According to recent mapping studies of technical debt [6], there is a lack of em-pirical studies on technical debt management approaches. This study can hopefullyfill some of that void by suggesting and testing solutions to manage technical debtin practice. The study of management approaches can not only help out in research,

1

Page 11: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 1. INTRODUCTION

but also Django developers as this study tries to suggest some guidelines in man-aging technical debt. By improving how Django developers think about technicaldebt in their applications, it is hopefully possible for them to minimize the costsof maintenance. As this report only discusses software development and technicaldebt in a broader terms, there has been no analysis done on the ethical aspects ofthis work.

1.2 Research questionsTo help define the concept of technical debt in the context of Django web appli-cations, the first research question asks what the main causes of technical debtare.

RQ1. What are the main causes of technical debt in Django web applications?It is then interesting to know the practices and tools available to manage this

technical debt. This makes it possible to find out how Django developers identifyand prevent technical debt.

RQ2. Are there practices and tools to manage technical debt in Django webapplications?

From knowing the causes of debt, and the practices and tools used to manageit, it should then be possible to set up some guidelines for how to best managetechnical debt when developing with Django web applications.

RQ3. Can we establish some guidelines for developing with Python and Djangoto manage technical debt?

1.3 Scope and limitationsTechnical debt does not only exist in code, but also in for example tests or infras-tructure. This thesis does not investigate all kinds of technical debt that mightoccur in a software system that uses Django, instead it focuses on code and designdebt. The typical infrastructure or documentation of a Django web application isnot much di�erent from any other web application, that is why such debt is notdiscussed.

The management of technical debt can be separated into several types of activ-ities, like measurement and communication. This thesis mainly talks about threetypes of activities; identification, prevention, and repayment. These are some ofthe main activities of managing technical debt, but with more time and resourcesother activities could have been evaluated as well. The case study that evaluatedmanagement of technical debt was only performed on one software project that usedDjango. With more time it would have been interesting to evaluate managementactivities on more projects.

2

Page 12: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Chapter 2

Background and Literature Study

This chapter gives a background to the metaphor technical debt and the recentresearch done on managing technical debt. Common causes of technical debt havebeen gathered from other papers and talks and are presented in a section below.The last section lists the di�erent activities done in technical debt management.

2.1 The technical debt metaphorThe term and metaphor technical debt was first coined by Ward Cunningham in1992 [1]. He described a situation where the long-term goal of software quality wastraded for short-term gain, creating technical debt.

“Shipping first time code is like going into debt. A little debt speedsdevelopment so long it is paid back promptly with a rewrite. [...] Thedanger occurs when the debt is not repaid. Every minute spent onnot-quite-right code count as interest on that debt. Entire engineeringorganizations can be brought to a stand-still under the debt load of anunconsolidated implementation.”

The metaphor helps us think about problems that are prevalent in softwareprojects, and it says that if we do things the “quick and dirty” way we will gettechnical debt. An example might be technical debt from a poor software architec-ture, that developers have implemented as a compromise to meet a deadline. Likefinancial debt, we need to pay interest on technical debt. In our example it would bethe extra time needed to implement a new feature because of the poor architecture.Either the developers can continue to pay interest, or they can pay back the wholedebt by refactoring the architecture.

When the term was coined in 1992 it saw little use, but around 2000 the termstarted to gain traction. It was mostly being used in blogs and essays as a term forall software problems. [3] Software engineers often advocate for investments in codequality and documentation, which might not generate short-term revenue, but are

3

Page 13: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 2. BACKGROUND AND LITERATURE STUDY

crucial to systems lasting quality. The term is then attractive to use for engineers,as a tool to communicate to managers the importance of software qualities.

2.1.1 Technical debt quadrant

The term was further defined when Martin Fowler in 2009 [2] proposed the technicaldebt quadrant. It came out of the argument if technical debt should be reserved forconsidered decisions that gives short-term gains but create debt in the long-term,while messy code created by programmers ignorant of good practices should notbe considered technical debt. Fowler suggested that instead of thinking in terms ofnon-debt and debt, that we di�erentiate between prudent and reckless debt.

Another dimension can then be added, with the di�erence between deliberateand inadvertent debt. Reckless deliberate debt comes from when developers dothings the “quick and dirty” way, while reckless inadvertent debt comes from lack ofknowledge. Prudent deliberate debt comes from when developers take on technicaldebt for a good reason, for example it might not be worth the time to implementthe perfect code design in a system that is rarely touched. The last type is thenprudent inadvertent debt that comes when developer realize after they have createda system what the perfect design should have been.

Table 2.1. Technical debt quadrant

Reckless Prudent

Deliberate

We don’t have time fordesign

We must ship now anddeal with theconsequences

Inadvertent What’s layering? Now we know how weshould have done it

2.1.2 Managing technical debt research

The topic of technical debt got further attention in 2010 when several researchersfrom di�erent institutes and universities met at the Carnegie Mellon Software En-gineering Institute. They published a paper [4] that sets the agenda for futureresearch in the field of managing technical debt, by establishing the workshop man-aging technical debt.

It says that research on managing technical debt can make the intuitive under-standing of technical debt into a more rigorous definition. Research can also help thetechnical community by clarifying the strengths and weaknesses of di�erent types

4

Page 14: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

2.1. THE TECHNICAL DEBT METAPHOR

of technical debt management. The paper suggest several open research questionsthat are listed below.

• The first research question is how we find refactoring opportunities. We mostlydepend on developers’ experience to detect debt, but there has been toolsdeveloped to detect symptoms of poor design in code. However such toolsare di�cult evaluate quantitatively, as it is hard to estimate the impact ofre-factorizations.

• While small local re-factorizations can improve a code base, system-widearchitectural issues often need larger e�orts. It can become a subjective mat-ter to evaluate if and how to re-architect a system. Having tools to measureand manage technical debt in architecture could help developers make moreinformed decisions.

• Identifying dominant sources of debt in di�erent contexts from field studies,can give directions on what research should focus on.

• Measurement of technical debt has been researched and there are many issueswith it. To make the measurements useful they need to be combined andcreated to help decision-making. The measurements should then be put intoseveral specific concepts. The first one is principal which is cost of eliminat-ing the technical debt. The second one is interest probability, which “is theprobability that a particular type of technical debt will in fact have visibleconsequences”[4]. The third one is interest amount which is the added cost ofperforming maintenance because of the technical debt.

• Non-code artifacts can also be subject to technical debt research, for examplehow technical debt occurs when test plans are not followed.

• Monitoring and visualization tools of technical debt could help provide insightinto when there is “too much” debt. To know if there is too much debt, thereneed to be some acceptability thresholds to be researched.

• To ensure that the technical debt metaphor leads to good practices, researchis needed to evaluate projects that have been launched to remove technicaldebt. To make techniques of removing technical debt explicit, current de-fined development processes should then be adapted to include tracking andmanagement of technical debt.

2.1.3 Types of technical debtA systematic literature review from 2014 [6] mapped 94 studies about managingtechnical debt. From the studies the paper collected what di�erent types of technicaldebt that had been identified, and it resulted in a classification of 10 types.

5

Page 15: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 2. BACKGROUND AND LITERATURE STUDY

1. Requirements technical debt is the di�erence between the optimal require-ments’ specification and what is actually implemented.

2. Architectural technical debt is the limitations of an architecture that for ex-ample impair maintainability.

3. Design technical debt is defects in the code design, for example having overlycomplex classes.

4. Code technical debt is poorly written code that does not follow the best prac-tices and standards.

5. Test technical debt refers to shortcuts taken when creating tests, for examplelow test coverage or inaccurate test cases.

6. Build technical debt refers to problems in the build system, for example thatit is hard to deploy code.

7. Documentation technical debt refers to insu�cient or outdated documentation.

8. Infrastructure technical debt refers to sub-optimal configuration of systems orproblems with development-related supporting technologies.

9. Versioning technical debt refers to problem with the version control system.

10. Defect technical debt refers to defects or bugs in a software system.

The paper [6] also tries to define what is not technical debt. It lists exampleslike unimplemented features and functionalities. Some types above are not strictlydefined, for example the problem of overly complex code or duplicated code can beidentified as both code and design debt.

2.2 Causes of technical debtThere are many causes of technical debt in software projects. Listed below are themain identified causes of technical debt, that have been chosen after review of whatother studies [6, 9] reported about technical debt.

This thesis puts the technical debt metaphor in the context of Django appli-cation, and it mostly discusses code and design debt. Other causes of debt likeversioning or infrastructure technical debt, are not specific to Django applications,and therefore such types are out of scope for this thesis.

2.2.1 Architectural issuesSoftware architecture refers to the high levels structures of a program. For examplehow di�erent modules communicate or what framework and programming language

6

Page 16: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

2.2. CAUSES OF TECHNICAL DEBT

that is used. There are many types of architectural issues that one can get. Ex-amples are over abstraction or lack of layering (instead of using for example theModel-View-Controller pattern). Architectural debt often comes from architecturaldecisions that made sense when the system first was built, but after the system hasgrown it now requires other patterns to solve its problem as best as possible.

2.2.2 Lack of adhering to coding style and conventions

Code is more often read than written, therefore it is important to make sure thatcode is readable. By following a style guide when coding, the readability can im-prove, as the code is consistent within the code base (e.g., using the same indentationpattern). Python has a de-facto style guide called PEP8, which should be followedfor projects to increase readability [7]. Lack of adhering to this code standard, orthe one decided upon in a project, is a form of technical debt.

2.2.3 Code duplication

Duplicated code occurs frequently in code bases, but it should be avoided. It mightoccur from copying and pasting code, as it is faster than writing code from scratch.It is however considered a bad practice. When developers need to fix a bug or makea change in the code, they will need to check all possible duplications for that fixor change. Code duplication often indicate that there are design problems in thecode, and that abstractions and re-factorizations can be done.

2.2.4 Dead and obsolete code

Dead, obsolete, or unreachable code is code that is never executed in a program orcode that does not do anything useful. This creates technical debt as it can confusethe reader of the source code, and make the code less clear. In large programmingprojects, it can become di�cult to recognize and delete dead code, as whole classescan be unused. The dead code might still have tests, but is actually never used inproduction.

2.2.5 Overly complex code

To make code maintainable developers should write their code as readable androbust as possible. This means that they should avoid creating overly complexcode, that might look elegant, but will be hard to understand by other developers.As the computer scientist Brian Kernighan wrote [11]: “Debugging is twice as hardas writing the code in the first place. Therefore, if you write the code as cleverly aspossible, you are, by definition, not smart enough to debug it.”

7

Page 17: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 2. BACKGROUND AND LITERATURE STUDY

2.2.6 Legacy software package dependencies

Developers often use external software packages in order to save time and resources.Making sure the external packages are of the latest version is important, as newreleases might include bug fixes, but also new features. When upgrading packages,each dependency is a potential problem or obstacle. Updating one package mightrequire other packages to be updated as well. Having to update all packages atonce can create many problems (e.g. APIs changing). Therefore, it is important tokeep all external packages up to date, to avoid any technical debt.

2.2.7 Lack of testing

Testing is an important part of software development. There are many types oftests like acceptance, unit, performance, load, integration or regression tests. Hav-ing extensive testing suites ensures that software changes do not break existingfunctionality. This eliminates bugs before they reach production. Having extensivetests will also make developers confident in that their program do what it is ex-pected to do, and does not do what it is not supposed to do. It is often impossible(and not economical) to get full test coverage, but having no tests is a cause fortechnical debt.

2.2.8 Poor tests

Tests for software programs are expected to be deterministic. A test should alwayspass or fail for the same code. In practice there are usually several flaky tests (dueto for example test order dependency) in large software projects [8]. To have anon-deterministic test mean that you can get false positive or false negative resultsfor the same test after running it several times. Such tests makes it di�cult to trusttest suites and is considered technical debt.

As code and requirements change, tests needs to be updated as well. If the testsare not maintained, they do only cause more problem than they help developers.Therefore, any poor and not up to date test is technical debt.

2.2.9 Lack of or outdated documentation

Many developers lack the motivation to document code, as they perceive it as a sec-ondary task compared to writing code. Some software development techniques evensay that code should be self-explanatory and that code comments are unnecessary.However, studies show that lack of or outdated documentation increases mainte-nance costs [10]. So wherever code is created without needed documentation, thereis technical debt. The documentation also needs to be up-to-date, as any outdatedor out-of-sync documentation only creates confusion.

8

Page 18: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

2.3. PYTHON AND DJANGO APPLICATIONS

2.3 Python and Django applicationsPython is a dynamic typed programming language, that supports both object-oriented and functional programming. Its syntax is intended to be highly read-able, and often uses English keywords rather than special characters. It also useswhitespace indentation, instead of curly braces which is common in other languages.According to the TIOBE Programming Community index, which measures the us-age of programming languages, Python is the 5th most popular language [12].

Django is an open-sourced web framework written in Python. It follows the ar-chitectural Model-View-Controller pattern. It also includes its own object-relationalmanager, internationalization system, template system, form serialization and vali-dation system and many other components. It also comes bundled with an authen-tication system and an admin interface, which is often one of the main selling pointsof the Django framework.

2.4 Django-specific causes of technical debtWhen talking about causes of technical debt in the context of Django web applica-tions, there are several Django-specific causes of technical debt. The main causesof technical debt in Django applications that have been identified are lised below,they were collected from talks [13, 14], books [15, 16, 17] and blog posts by Djangodevelopers.

2.4.1 Monolithic Django appsIn the Django framework small libraries are called apps. A Django project oftenconsist of several apps that each has their own responsibility. They should bekept small so that they are potentially shareable between di�erent projects. JamesBennett, one of the core developers of Django, said in a talk [18] that one shouldwrite apps that “do one thing and do it well”.

Some Django projects consists of one large monolithic app, that contain most ofthe features for the whole site. Large monolithic apps are often hard to understand,in comparison to small well-defined apps. These large apps often encourage andenable tightly coupled code, which makes it hard to break out code or make changes.

2.4.2 Misuse of signal receiversSignals are used in Django to notify when an action occurs, for example when amodel is created or when a HTTP response is finished. A receiver can be set up totake some action upon that signal. This concept is not unique to Django, it existsin many other languages (for example Java has listeners and events).

Below is an example of a signal receiver, that is executed after the model My-Model is saved.

9

Page 19: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 2. BACKGROUND AND LITERATURE STUDY

1 from django.db.models.signals import post_save2 from django.dispatch import receiver3 from myapp.models import MyModel4

5 @receiver(post_save, sender=MyModel)6 def my_handler(sender, **kwargs):7 pass

Signals are often unnecessary and can create code obfuscation. For example thepost save code example above, could have been put in the model itself, where othermodel operations exist. One of the core Django developers Aymeric Augustin says[15]:

“I advise not to use signals as soon as a regular function call will do. Signalsobfuscate control flow through inversion of control. They make it di�cult to discoverwhat code will actually run.”

Many developers [15] also make the mistake to think that signals are asyn-chronous, when they in fact are synchronous and blocking.

2.4.3 Overuse of middleware and context processorsMiddlewares in Django are used to hook into the process of every incoming requestand outgoing response that reaches the application. It is common to use middle-wares to log requests, compress response content or cache responses. These taskscould be done in each individual view, but that would require a lot of boilerplatecode that the middleware class removes.

Figure 2.1. Shows the flow from request to response.

Context processors are similar to middlewares, but these processors are run over

10

Page 20: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

2.4. DJANGO-SPECIFIC CAUSES OF TECHNICAL DEBT

the context that is passed to templates. They provide common information for alltemplates, for example data that is kept in the footer and header of a website.

While both middlewares and context processor are useful to avoid repeatingoneself in the code, it can be misused. If heavy operations or large database queriesare executed in middlewares or context processors, they can impair performance.As they are executed for every response, request or template it is important they arekept minimal and well performing. If business logic is hidden in context processoror middlewares, it might also confuse the reader of the code, as it is not the obviousplace for such code to exist.

2.4.4 Heavy queries from Django ORMDjango comes with an ORM (object-relational mapping) that is used to interactwith the database. With an ORM developers do not have to write SQL code, andcan instead write database queries in Python. The Django ORM is often e�cientin its job, and it simplifies a lot of databases interaction for developers. But it alsocomes with its disadvantages, critique from the Django community [21, 22] is thatthe ORM is inconsistent and that it lacks composability.

It is possible to use the Django ORM in a wrong way, causing performanceproblems. Developers may create heavy and complex queries using Python and theORM, when the calculation could have been done better at the database level (witha raw SQL query). In an example made by Greg Gaughan [23], we assume there isa model of a Book.

1 class Book(models.Model):2 title = models.CharField(max_length=100)3 author = models.ForeignKey(Author)4 jacket = models.ForeignKey(Jacket)5 shelf = models.ForeignKey(Shelf)

In the view, the books are fetched with the following query.

1 books = Book.objects.filter(shelf__position__lte = 10)

The books are then listed in the template.

1 {% for book in books %}

2 {{ book.jacket.image }} {{ book.title }}

3 by {{ book.author.name }}

4 {% endfor %}

11

Page 21: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 2. BACKGROUND AND LITERATURE STUDY

It might seem as a simple operation, but it will make 21 queries to the database.First one to fetch the 10 books (one for each shelf position), then when iterating inthe template, 2 queries for each book to fetch related models. It could have beendone with only one query:

1 SELECT2 book.id, book.title,3 jacket.image AS jacket_image,4 author.name AS author_name5 FROM book6 NATURAL JOIN shelf NATURAL JOIN author NATURAL JOIN jacket7 WHERE shelf.position <= 10

The raw SQL query above can be created with the ORM as well (using se-lect_related to perform joins). But the example shows a common problem, and thetechnical debt that a lot of Django projects have with unnecessarily heavy queriesfrom the Django ORM.

2.4.5 Django models become god objectsIn Django code it is not always obvious where one should put business logic. Someprefer to keep the logic in their models [19]. This can be problematic, as the modelsmay become god objects. This anti-pattern [20] refers to objects that does toomuch. The models hold so much data and functionality and they are required byso much of the code that they become “god like”. As they grow larger, they mightbecome hard to understand. They are hard to maintain as well, as they are sotightly coupled with the rest of the code.

2.4.6 Complex template hierarchiesTo generate HTML dynamically Django has a template language. It makes it pos-sible to use constructs like if conditions, and for loops embedded in the HTML. Oneof the most useful parts of Django’s template engine is the template inheritance.Developers create a base template, with all the common information of the site, andthen let child templates extend and override parts of the base template.

An example of a base template from the Django tutorial [24]:

1 <!DOCTYPE html>2 <head>3 <link rel=’stylesheet’ href=’style.css’ />4 <title>{% block title %} My amazing site{% endblock %} </title>5 </head>

12

Page 22: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

2.5. TECHNICAL DEBT MANAGEMENT

6

7 <body>8 <div id=’content’>9 {% block content %}{% endblock %}

10 </div>11 </body>12 </html>

A child template can then extend the base and override blocks like content andtitle.

1 {% extends "base.html" %}

2 {% block title %}{{ block.super }} - Child template{% endblock %}

3 {% block content %} This is the content!{% endblock %}

Two-tier template architecture like above, works really well. However, as web-sites grow, it is possible to further extend and create deeply nested template hier-archies. While it is advantageous to avoid any code reuse, creating overly complextemplate blocks can be as bad. This can create systems that are di�cult to debugand modify. [15]

2.5 Technical debt managementTo prevent technical debt and deal with existing technical debt there are severalactivities that are done, and they can be summarized into the list below.

• Technical debt identification is the activity of detecting technical debt, withfor example code analysis. By analyzing the source code to find violations ofcoding standards, lack of tests, or by looking at software metrics to identifydesign issues.

• Technical debt measurement quantifies the cost of maintaining the technicaldebt in a system. This can be done with calculation models, code metrics,and human estimations.

• Prioritization of technical debt ranks the identified issues, so the most urgenttechnical debt can be repaid first.

• Prevention of technical debt is done to limit any future technical debt. Thiscan be done by for example improving the development process, so that de-velopers have to follow best practices.

• Monitoring of technical debt follows the changes in technical debt over time.

13

Page 23: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 2. BACKGROUND AND LITERATURE STUDY

• Repayment of technical debt resolves technical debt in a software systemwith for example refactoring.

• Technical debt documentation refers to ways to document technical debt,often with the usages of what’s called a “TD item”. There is no strict definitionof a TD item but it usually contains information as who is responsible forrepaying the item, where the location the debt is and the estimated cost ofrepaying the debt.

• Communication of technical debt makes the “TD items” visible to stake-holders, for example by putting them on a dashboard or backlog.

The three most fundamental activities for managing technical debt are identi-fication, measurement and repayment. These three types of activities to managetechnical debt have also been given the most attention in research [6].

14

Page 24: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Chapter 3

Method

The results in this report are supported by three activites. First the literature studythat gives a background and support to the conclusions of the work. Secondly asurvey on technical debt, with content from the literature study, was done to furtherdefine the concept of technical debt in the context of Django web applications.Thirdly, and lastly, a case study was done where di�erent solutions on how tomanage technical debt was tested and evaluated on a Django project.

3.1 Survey on technical debt

A survey was used to identify what software engineers think is the main cause oftechnical debt in Django web applications. It was through a questionnaire thatdevelopers were asked about their experiences and opinions about technical debt.This method [5] makes it possible to collect quantitative but objective data.

The survey was sent out to developers at companies that use Django. The surveywas inspired by a paper [9] that researched what the industry believes in generalabout technical debt. The survey done for this thesis put the concept of technicaldebt was in the context of Django.

The survey asked if the respondent is familiar with the concept of technicaldebt. If not, a definition was presented. The survey then asked how many yearsof experience with Django the respondent has and what role he or she has whenworking with Django (for example Software Architect or Software Engineer). Thenit asked what causes for technical debt occurs in their typical Django project. Bylisting the causes of debt that are mentioned in the background, the respondentcould choose to answer if they often occur, sometimes, never or if it’s not applicable.Finally, the survey asked what tools that are used to manage technical debt in theirtypical Django project.

15

Page 25: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 3. METHOD

3.2 Case study of managing technical debtTo test out approaches of managing technical debt, several tools and practices wereevaluated on a code base in a Django project. The evaluation of the tools was madein a project that was currently being developed on. The tools were then tested outin a context of being a developer, to make the evaluations close to a real worldsituation of managing technical debt. When evaluating all the tools, predefinedcriteria were used (and they are described in the section 3.2.2).

3.2.1 Test code baseThe tools were tested with an existing Django project described below.

• The total number of lines of code are 5545.

• It has 8 contributors during its lifetime.

• Development started in October 2008 and has been active until today.

• It runs Django 1.5, and has over 14 other Python package dependencies.

• The database MySQL is used, and it’s schema has been changed multipletimes during the project’s lifetime.

3.2.2 Evaluation criteriaWhen evaluating tools of identifying, repaying and preventing technical debt, thefollowing criteria were used.

• Cost of usage. How easy was it to use and set up the tool? Are the reportsfrom the tool understandable?

• Technical debt impact. Did the tool identify, repay or prevent technicaldebt that had high value and critical symptoms?

• Interest amount saved. How much extra work would be needed in futuredevelopment, if this technical debt had not been prevented or identified andrepaid?

• Accuracy. How well did the tool accurately identify or prevent technical debt(or did it find false positive results)?

16

Page 26: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Chapter 4

Results

The results are divided in two parts. First the responses from the survey are pre-sented in charts and figures with explanations. The second part is the evaluationsof tools to identify, repay and prevent technical debt. Each tool is first described,and then comes the evaluation of how well the tool worked in the project.

4.1 Survey responsesThere were 23 responses from Django developers about technical debt and theirexperience in managing it. There is no measured response rate, but the survey wassent out to 8 di�erent companies and organizations that uses Django.

4.1.1 Demographic informationThe majority of the respondents were familiar with the concept of technical debt,as can be seen in figure 4.1.

Figure 4.1. Familiar with technical debt.

Yes

83%

No

17%

17

Page 27: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 4. RESULTS

The vast majority of the surveyed had the role of developer or software engineer.Of the 23 respondents, 20 were software engineers or developers, 2 were softwarearchitects and 1 was a project manager. Most of the respondents had between 1 to5 years of experience with Django, as can be seen in figure 4.2.

Figure 4.2. Experience with Django.

0 5 10

More than 5 years

3-5 years

1-2 years

Less than 1 year

4.1.2 Cause of technical debtThe respondents were asked what is causing technical debt on their typical Djangoproject. The answers to general types of technical debt can be seen in figure 4.3and the Django-specific types are in figure 4.4.

0 5 10 15 20 25

Poor tests

Lack of adhering tocoding style and conventions

Code duplication

Dead and obsolete code

Lack of oroutdated documentation

Legacy softwarepackage dependencies

Overly complex code

Lack of testing

Architechtural issues

Time in SecondsOften Sometimes Never Don’t know/not applicable

Figure 4.3. Cause of technical debt.

18

Page 28: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

4.2. EVALUATIONS OF TOOLS AND PRACTICES IDENTIFYING TECHNICALDEBT

0 5 10 15 20 25

Overuse of middlewaresand context processors

Misuse of signal receivers

Heavy queries fromDjango ORM

Complex template hierarchies

Django models becomegod objects

Monolithic Django apps

Time in SecondsOften Sometimes Never Don’t know/not applicable

Figure 4.4. Cause of Django-specific technical debt.

When asked about what tools developers used in their typical Django projectto manage technical debt, most answered error logging aggregation and code styleand error analysis.

Figure 4.5. Tools used to manage technical debt.

0 5 10 15

Dead code detection

Test coverage

Code style and error analysis

Error logging aggregation

4.2 Evaluations of tools and practices identifying technicaldebt

The tools for identifying technical debt that have been evaluated in this thesis canbe put into three di�erent categories. The first one is logging aggregators, thesecond one is application monitoring and the third one is static code analyzers.

19

Page 29: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 4. RESULTS

4.3 Logging aggregatorsWhen something goes wrong in a Django web application, it saves an error log en-try. Informational or debugging logs are also saved to better understand how anapplication works. As applications grow, so will the amount of log entries. There-fore, it is useful to aggregate logs and present them in a format so that developerscan investigate the most important problems. If a web application runs on multipleservers, then it becomes even more important to put all logs in one place. Beloware two log aggregation tools that have been evaluated.

4.3.1 SentrySentry aggregates logs and presents them in a web interface where it is possible toview the most common events and errors. It can also give alerts to users if thereis a sudden spike in errors, or if new unique errors occur. This makes it easy fordevelopers to tackle the most critical errors in an application. A screenshot of theSentry dashboard can be seen in figure 4.6.

Figure 4.6. Sentry dashboard

The installation of Sentry for Django can be very easy if one decides to pay$29 per month for Sentry’s hosted service. It only requires a few minutes workand everything is set up. There is also the free option of hosting Sentry on yourown server. This however should be done with caution as error reports will not beaccessible if your own server goes down. In many cases it might be more reliable tohost Sentry with a third party.

For all error logs Sentry gives a lot of context that is really useful when debuggingerrors. In the error reports there is information such as release version of the codebase, readable HTTP headers, and well formatted tracebacks. It is also possible

20

Page 30: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

4.3. LOGGING AGGREGATORS

to search among the logs, filtering by time or content. All these features makes iteasier to identify visible technical debt. Hidden technical debt, for example scalingissues, will not be observable with this tool.

4.3.2 ElasticSearch, Logstash and KibanaOne of the most powerful ways to aggregate logs is to use the ELK-stack (Elas-ticSearch, Logstash and Kibana). Logstash is responsible for collecting logs andparsing them. The formatted logs are then stored in ElasticSearch, which is a textsearch engine. On top of these tools is Kibana which is a web interface to presentdata from ElasticSearch. Together the ELK-stack can be used to present aggregatederror logs. With further configuration you can also add alerts for error spikes orunique errors.

Figure 4.7. Screenshot of Kibana

It requires a lot of work and configuration to install the ELK-stack. Todaythere are no packages to send formatted logs from Django to Logstash. This meansthat some configuration of Logstash is required to parse the standard Django logs.Kibana also has many features which can make the interface hard to learn andunderstand, this means it can be di�cult to create a dashboards in it. If there is aneed to set up an alert system, that will be more configuration.

All in all; this system requires extensive knowledge for it to be used. It will alsohave to be maintained, which might create more technical debt for the developersthan it will be able to identify. The ELK-stack should not be used for only Djangologs, as it is too much infrastructure to maintain. When there is need to display

21

Page 31: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 4. RESULTS

more custom logs, the ELK-stack is probably better suited as it can be customizedheavily.

4.4 Application monitoring

Monitoring tools are used to analyze and display information about a web appli-cation’s execution. The information makes it possible for developers to identifyand fix problems. They can for example monitor database query performance ortemplate rendering times.

4.4.1 New Relic

New Relic agent is web monitoring service, it costs $75 per month to use. The servicemonitors response times, database queries, error rates, CPU use, and uptime forweb applications. The reports and monitoring can be viewed in a web interface.

One of the most useful features of New Relic agent is the reporting of slowloads in an application. Slow loads can then be investigated through transactionstraces, to see if the problem lies in the view handler, calls to external services,a middleware, template rendering or the database. This makes it easy to tackleperformance problems.

Figure 4.8. Transaction trace in New Relic

22

Page 32: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

4.4. APPLICATION MONITORING

It is very easy to deploy New Relic’s monitoring system as it is just a Pythonpackage that needs to be installed and a small modification of the Django’s start upscript. From testing out New Relic and learning about all of its features, it is a reallygood tool to tackle technical debt. It gives great introspection into its monitoredDjango application, making it easier to improve its performance. However, whenusing it with the “test Django project” it is hard to find improvements to make. In alarger Django web application with more tra�c, a tool like New Relic can probablygive better insight.

4.4.2 AppEnlight

AppEnlight is an application monitoring system, it is free to use but it is not opensource. As it is a hosted service, it might cost to use in the future. AppEnlight’sreports can be viewed through their web interface. It reports slow calls and breaksdown what time is spent in what request layer (middleware, template, view, etc).It will also report on slow SQL calls, so that the queries can be improved forbetter performance. This is helpful when an application is performing badly, andimprovements need to be made. When using AppEnlight with the test project, itdid not report any slow database calls or other information that could be used toimprove performance. It is easy to install AppEnlight though, as it only requirestheir Python package and some changes to Django’s settings.

Figure 4.9. Screenshot of AppEnlight

23

Page 33: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 4. RESULTS

4.5 Static code analyzersThe static code analyzers that were evaluated were pep8, Pyflakes, Flake8, Pylintand Vulture. They all have checks to see that the analyzed code is formatted ina correct matter. All of them are very popular packages for Python and they areconsistently downloaded thousands of times per month (see table 4.1).

Table 4.1. Statistics from PyPi in January, 2015. [26]

Tool Last updated Downloads per monthpep8 2016-01-12 937670Pyflakes 2015-09-20 669146Flake8 2015-12-15 572869Pylint 2016-01-15 370066Vulture 2015-09-28 3541

A comparison of the supported functionality for the di�erent tools can be seenin table 4.2.

Table 4.2. Functionality (checkers) for the static code analyzers.

pep8 Pyflakes Flake8 Pylint VultureCoding standard X X XNaming conventions X XDocstring conventions X XErrors X X XComplex code X XDuplicated code XDead code X X

4.5.1 pep8This tool checks Python code to see if it is compliant with the coding standardPEP8. The PEP8 standard [7] defines how indentation should be done, how stringsshould be constructed, how long lines should be, and much more.It is executed fromthe command line, and output from an example run can be seen below:

prime/forms.py:15:1: E302 expected 2 blank lines, found 1prime/forms.py:20:1: E302 expected 2 blank lines, found 1prime/forms.py:24:1: W293 blank line contains whitespaceprime/forms.py:25:1: W293 blank line contains whitespaceprime/forms.py:30:8: W291 trailing whitespaceprime/forms.py:31:80: E501 line too long (82 > 79 characters)

24

Page 34: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

4.5. STATIC CODE ANALYZERS

prime/forms.py:32:1: W293 blank line contains whitespaceprime/forms.py:41:8: W291 trailing whitespace

The tool is very easy to set up, as it only requires a Python package to beinstalled. The reports are also very understandable and it only takes pep8 about 3second to run through the entire code base of 5000 lines. The technical debt impactfrom not following the PEP8 standard can be seen as very low though, as it doesnot identify any critical errors in code (even if most Python projects should followPEP8 as it is the de-facto coding standard for Python).

4.5.2 PyflakesPyflakes analyzes programs and detects defects such as unused imports, assignmenterrors, return statements outside of methods or functions, and many more errorsand warnings. Here some output from an example run:

wishlist/forms.py:2: ’IntegerField’ imported but unusedwishlist/forms.py:3: ’HiddenInput’ imported but unusedwishlist/forms.py:4: ’ForeignKeyRawIdWidget’ imported but unusedwishlist/forms.py:7: undefined name ’platform’wishlist/forms.py:20: redefinition of unused ’models’ from line 5

Pyflakes is easy to set up and use as it is only a Python package that needsto be installed. Pyflakes can theoretically find errors that can have big impact ontechnical debt, but in the Django project that it was tested against it only foundmodule imports that were unused. Unused imports will slow down the start uptime, and it might clutter the namespace, but other than that it is not a big issue.

4.5.3 Flake8Flake8 is a wrapper around three other tools called Pyflakes, pep8 and Ned Batchelder’sMcCabe script. Pyflakes and pep8 have been described above, and the McCabescript calculates cyclomatic complexity for functions. It is a measure to calculatethe complexity of a program, and it can give warnings when code is regarded as toocomplex.

Together it creates a powerful tool that gives you a lot of information about howyou should structure your Python code to keep it consistent, readable and correct.It has the same kind of output as pep8 and pyflakes, so the results are very easy tounderstand, but the identified problems can be categorized as having low technicaldebt value when tested against the Django project used in this report. The tool isvery fast, and it takes only a second to run it over the entire code base.

25

Page 35: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 4. RESULTS

4.5.4 PyLintPyLint is one of the most comprehensive static code analyzers for Python. It checksfor coding standard, dead code, duplicated code, naming conventions and muchmore. When testing with the test code base, it outputs a huge report. With thedefault configuration the report contains over 30 000 lines. Most of the reportedissues will also be of little importance (causing little technical debt). Examples are“missing trailing whitespace”, and “variables names of too few characters”. To getany useful information of PyLint, one must choose what errors and warnings to use.

It is also di�cult to set up PyLint. It might just be the tested code base that ithas problems with, but there are several Python files that PyLint cannot process.Therefore, several files had to be excluded for the tool to work. There were alsoencoding errors when trying to export the results as HTML. When running the toolover the entire code base, it takes over 4 minutes for PyLint to finish.

4.5.5 VultureVulture is easy to set up to identify dead code, but Vulture has several issues with theDjango framework. As Django uses variables names and classes implicitly, Vulturewill mistake a lot of these variables and classes for dead code. Examples of wronglyidentified dead code are management commands, migration files, middlewares, tests,admin options, model variables, form variables and settings variables. Most of thecorrectly identified lines from vulture are unused classes and functions. Thereforeit can not be said that Vulture has good accuracy when trying to identify technicaldebt.

A comparison between PyLint and Vulture’s dead code detection can be seenin table 4.3. It should be noted though that most of the dead code found fromPyLint was unused imports and variables, while Vulture identified unused classesand methods.

Table 4.3. Accuracy of dead code detection tools.

Tool Lines of unusedcode identified

Lines of unusedcode identified, aftermanual verification

Accuracy

vulture 184 occurrences 27 occurrences 14 %pylint 103 occurrences 103 occurrences 100 %

4.6 Evaluations of tools and practices to repay technicaldebt

4.6.1 Tombstone decoratorsIn a large code base it might hard to determine whether a class or a functionis used or not. In order to solve such a problem, one can use the practice called

26

Page 36: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

4.6. EVALUATIONS OF TOOLS AND PRACTICES TO REPAY TECHNICAL DEBT

“tombstones”. By marking a function with a tombstone decorator (see code examplein listing 1), it will save a log entry if the function is executed. If such a log entryis then created, we will know that the code actually is used, and that it should notbe removed. If a function has not been used for a certain period of time, we willconclude that the function is indeed “dead” and not used, and we can safely removeit.

1 @tombstone2 def example_function():3 pass

Listing 1: A function marked with a tombstone decorator

The problem with using tombstones decorators is that they require too muchwork to just detect dead code in Python. Developers using tombstones will haveto maintain the tombstone code and its logs, to make sure they work as intended.This maintenance will create more technical debt, than the removal of dead codewill repay.

4.6.2 Automated code formattingThere are several tools to automatically fix code formatting issues in Python. Thethree tools tested are isort, autopep8, and autoflake. To sort Python imports al-phabetically and to separate them into sections, isort can be used. To format codecorrectly, autopep8 will fix most formatting issues in accordance with the PEP8-standard. Finally autoflake removes any unused variables or imports. An exampleof a badly formatted code can be seen below.

1 import math2 import sys3

4 class ClassExample( object ):5 def __init__ ( self, val ):6 #There should be a space after the hash in comments.

7 if val : val+=1; val=val* val ; return val8 return sys.path

After running the tools on the code example, it will then be formatted correctlyand unused imports are removed:

1 import sys2

27

Page 37: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 4. RESULTS

3

4 class ClassExample(object):5

6 def __init__(self, val):7 # There should be a space after the hash in comments.

8 if val:9 val += 1

10 val = val * val11 return val12 return sys.path

When running these tools over the entire code base, they work really great. Itmakes sure that the code is readable and consistent. It is also really easy to usethese tools, as they are just Python packages that needs to be installed. There aresome exceptions to what these automated tools can do though, if for example non-standard libraries are imported but unused, they will not be removed automaticallyas they might have side e�ects that are intended.

4.7 Evaluations of tools and practices to prevent technicaldebt

4.7.1 Pre-commit hooksFor projects that use version control, it is possible to add hooks that run whendevelopers are committing code. This way it is possible to run “sanity checks” onall the code that is added or changed in a source code repository. The hooks thatrun on the added or changed code can be any program or code analyzer. To make iteasy to add pre-commit hooks to git, there is the Python package called pre-commit.

The installation of pre-commit is very easy, and there are several hooks thatalready exists for Python. Pre-commit hooks are very useful, as they can be usedto coordinate several developers to standardize their code consistently. Hooks canthen make sure that all developers are running the same automated code formattingtools or that any deprecated function name is not included in the added file.

As pre-commit hooks are only executed over the changed files, it is useful touse these hooks to make big refactorization e�orts. Instead of for example tryingto change the usage of a deprecated function in the whole code base, we can makesure that incremental changes are made with pre-commit. This makes pre-commitvery useful in preventing technical debt, and also in repaying it.

4.7.2 Deprecation decoratorsAs systems grow, some features or functions become suspended as they are notrecommended for use anymore. It might not be possible to remove some functions

28

Page 38: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

4.7. EVALUATIONS OF TOOLS AND PRACTICES TO PREVENT TECHNICALDEBT

that are widely used in a system though. A good compromise is then to deprecatesuch a function, by giving out warnings about its usage. The Python packagedebtcollector helps in deprecating Python functions and methods. An exampleof using debtcollector’s deprecation decorators can be see below, where the openmethod is deprecated.

1 from debtcollector import removals2

3 class Project(object):4 @removals.remove5 def open(self):6 pass

If one were trying to use the open function, then the command line will print:

__main__:1: DeprecationWarning: Using function/method’Project.open()’ is deprecated

This can help developers from making the mistake of using deprecated functions.The package also include decorators for situations when a function is moved orrenamed as well. It will require that developers are disciplined enough to look forwarnings in new code, as the deprecated code might still work as expected. It washard to test out the usefulness of using deprecation decorators though, but if itmakes any developer not use any deprecated function, it can be said to preventtechnical debt. It is probably most useful in large projects where many developerssimultaneously develop on the same code base.

29

Page 39: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE
Page 40: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Chapter 5

Discussion

An interpretation of the survey results are done in this chapter, and then a shortanalysis on how the definition of technical debt can change the responses that weregiven. From the evaluation some guidelines are given on how to best manage tech-nical debt in a typical Django project.

5.1 Interpretation of survey results5.1.1 Familiarity with technical debtThe results show that most (83 %) of the surveyed already were familiar withthe concept of technical debt. This shows that the concept of technical debt is wellknown amongst Django developers. Other studies [9, 3] have reported that technicaldebt is a well used concept in the industry, so this was not a surprise.

5.1.2 Causes of technical debtWhen developers were asked what was causing technical debt in their typical Djangoproject, the two top answers were “architectural issues” and “lack of testing”. Over43 % said that both of these issues were causing technical debt often. The thirdmost reported cause, with 30 % saying it occurs often, is “overly complex code”.

When other studies surveyed developers about technical debt, they came to verysimilar results. The big survey [9] saw “bad architecture choices” as the main causeof technical debt, with “overly complex code” as the second most common, while“inadequate testing” was named the fourth most common cause. That the resultsare so similar are not surprising as all these kinds of technical debt are very generaland can be applied to most projects. The fact that the questions were asked in thecontext of Django applications seems to not have had any di�erence.

“Lack of testing” is a common cause of technical debt, so we can only assumethat many Django projects lack tests. One of the least reported cause of technicaldebt is poor tests, which might be because it requires large tests suite for suchproblems to occur frequently in the first place.

31

Page 41: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 5. DISCUSSION

From the answers of the Django-specific technical debt causes, we can see thatmonolithic Django apps, Django models becoming god objects and complex tem-plate hierarchies were the three most reported causes. They can all three be seenas subsets of “architectural issues” and “overly complex code”, which were alsoreported as causing technical debt often.

With this information it is possible to answer the research question “What arethe main causes of technical debt in Django web applications?”. The answer to thatis badly implemented architecture, lack of tests and overly complex code. This canthen manifest itself in a Django project, with monolithic Django apps or too largeDjango models.

5.1.3 Definition of technical debtThe definition of technical debt was not discussed in this survey, but it has beenshown that there can be several interpretations of the metaphor. If the developershave di�erent definitions for what is considered technical debt, then the replies onwhat is causing technical debt can be hard to analyze. When other studies havesurveyed definitions of technical debt [9], they have used similar methods as thispaper, and they also came to the conclusion that the industry had similar definitionsof technical debt as the science community. This is expected as the concept oftechnical debt did not originate from research, but became popular in the softwareindustry first.

5.2 Guidelines when developing with Django to managetechnical debt

From evaluating and testing tools on a Django project, there were several toolsthat worked really well to manage technical debt. Some of the tools might not benecessary to use, while others should be used in all projects. Below is an analysis,and some guidelines, for how to develop with Django and how to manage technicaldebt on a typical Django project.

5.2.1 Follow code standards with help of static code analyzersEven though the survey showed that “lack of adhering to coding standards” is rarelycausing technical debt in Django projects, there are still tools that exist for doingstyle checks that should be used. They require very little to set up, but will make iteasy to keep code bases consistent in style. Therefore any Django developer shouldmake use of such tools, to make the code as readable as possible. From the resultswe can see that the most comprehensive analyzer was flake8. Not only does itcheck for PEP8-standard in Python code but it also tries to find errors.

The alternative to flake8 would be PyLint, but as it can take over 4 minutesto run the tool over the code base, it is not optimal to use. If one has to waitfor too much time it will only hinder development and the tool will become a

32

Page 42: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

5.2. GUIDELINES WHEN DEVELOPING WITH DJANGO TO MANAGETECHNICAL DEBT

nuisance. PyLint also requires a lot of configuration to set up, compared to thedefault configuration of flake8 which is to be better suited for Django projects.

5.2.2 Use Sentry to aggregate logs

To have all error, warning and informational logs in one interface is very useful.It makes it easy to investigate problems that occur so that is it possible to fixthe problem. That is why Sentry is really recommended being used for loggingaggregations. Compared to the ELK-stack it is very easy to set up, Sentry alsoneeds very little maintenance which keeps the technical debt low.

5.2.3 If there are performance issues use application monitoring

For a small application, like the one that was tested, it might not be necessaryto have application monitoring. For the tested project it was hard to find anyimprovements to make with the application monitoring, as can be seen in the re-sults. Improving performance might not be an application problem, instead betterinfrastructure or front-end improvements might be more e�ective.

If an application has a lot of tra�c, and has a problem with performance, then itcan be useful to use application monitoring. Such tools will then be able to identifytechnical debt causes like “overuse of middleware” and “heavy queries from DjangoORM”. Currently New Relic has the most features, however AppEnlight is a goodfree alternative.

5.2.4 Deprecate functions with Python decorators

As seen in the results, there are high quality Python packages that can be used towarn about deprecated functions with Python decorators. Deprecating functions ormethods can often be easier than trying to refactor the whole code base to removethe deprecated function calls. By using deprecation the developers will not have todebate the cost versus benefit of “removing” a certain function. Deprecation willcreate some technical debt, but it will at least be deliberate and visible debt thatcan be dealt with in the future in a planned matter.

5.2.5 Prevent technical debt with pre-commit tools

Pre-commit hooks should be used in all Django projects. These hooks make itpossible to keep development practices consistent for all developers. For exampleto make sure that tests pass before developers commit code, or that no deprecatedfunctions are added to the source code repository. As it is really easy to implement(see results 4.7.1), it makes pre-commit hooks a cheap way of doing “continuousintegration”.

33

Page 43: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 5. DISCUSSION

5.2.6 Active identification of dead code might be unnecessaryIn the survey, few developers thought that dead code was a common cause of tech-nical debt. The tools that exists for detecting dead code are also not that accurate.For example the static analyzer Vulture can be avoided, as seen in results 4.5.5, be-cause it does not find results that are accurate because of how Django uses variablesand classes “implicitly”. The practice to use tombstone decorators to conclude if aclass or method is indeed dead is also not optimal. The maintenance of tombstoneswill create more technical debt than the removal of dead code will repay.

5.3 Reliability of the resultsThe evaluation of tools to manage technical debt was only carried out in one Djangoproject. Depending on the size of project, the numbers of developers, and theamount of tra�c the web application has, the challenges of managing technicaldebt will be di�erent. This study has to be seen as one evaluation of many, andthe conclusions are based on the experience from this “case study”, which could bedi�erent from others.

The distinction between repayment, prevention and identification of technicaldebt is also not always clear. There are no strict definitions for the terms, whichmeans is that some tools and practices can be hard to put into one category.

34

Page 44: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Chapter 6

Conclusions

From the survey it was concluded that the two main causes of technical debt inDjango projects are architectural issues and lack of testing. As discussed in 5.1.2it was in line with another big study [9] on causes of technical debt. The Django-specific causes of technical debt that were most frequently reported were “monolithicDjango apps” and “Django models become god objects”. Both of them can be seenas types of architectural issues and overly complex code. The surveyed Djangodevelopers therefore confirm that the causes of technical debt in Django are similarto other systems.

To prevent architectural issues, experienced developers have to make sure thatthe code follow best practices with regards to design patterns. Other causes oftechnical debt can be identified automatically with tools. From the evaluation oftools to manage technical debt it was found that there are several tools to help inkeeping a Django code base healthy. Several guidelines were then proposed fromthe evaluation, such as static code analyzers should be used to keep a consistentcode standard, in order to improve the readability of the code. The aggregationof error logs with tools like Sentry were also found to be useful, as it helps withidentification of any errors or bugs. For projects that have performance issues,application monitoring tools like NewRelic can be used to identify any slow databasequeries or templates renderings. Pre-commit hooks are a cheap way of making surethat development practices are shared in a project (for example that all tests arerun before making changes to a code repository). The identification of dead codewere not found to be useful with the Django framework, as the tools tested did notaccurately find unused code.

As said in the motivation 1.1 there is lack of empirical studies on managementapproaches to technical debt. This study and evaluation of tools can be said tofill some of that void, as it gives a practical view of how developers can managetechnical debt.

35

Page 45: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

CHAPTER 6. CONCLUSIONS

6.1 Future workFor future work of managing technical debt, it would be interesting to comparehow smaller projects are handled di�erently to larger projects. The approachesto managing technical debt will be di�erent, as the cost of setting up tools andinfrastructure to manage debt will be much larger in a smaller project. The cost tobenefit analysis will be more important for small teams, while larger organizationscan a�ord to use more elaborate approaches.

This thesis focused on technical debt in code and design, but it would be goodfor research to look at the management of technical debt for infrastructure andbuild systems. For example how to limit technical debt in “continuous integration”.This report did also mostly focus on the prevention, repayment and identificationof technical debt. It would be interesting then to see how it would be possible tointegrate the concept of technical debt more deeply into existing “agile methods”and its tools. For example by looking at the optimal way of documenting andcommunicating technical debt with tools like issue trackers.

36

Page 46: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

Bibliography

[1] Cunningham, Ward. “The WyCash portfolio management system.” ACM SIG-PLAN OOPS Messenger 4.2 (1992): 29-30.

[2] Fowler, Martin. “TechnicalDebtQuadrant.” 2009. 23 Dec. 2015 <http://martinfowler.com/bliki/TechnicalDebtQuadrant.html>

[3] Kruchten, Philippe et al. “Technical debt: towards a crisper definition report onthe 4th international workshop on managing technical debt.” ACM SIGSOFTSoftware Engineering Notes 38.5 (2013): 51-54.

[4] Brown, Nanette et al. “Managing technical debt in software-reliant systems.”Proceedings of the FSE/SDP workshop on Future of software engineering re-search 7 Nov. 2010: 47-52.

[5] Singer, Janice, and Dag IK Sjoberg. Guide to advanced empirical software engi-neering. Forrest Shull. Germany: Springer, 2008.

[6] Li, Zengyang, Paris Avgeriou, and Peng Liang. “A systematic mapping studyon technical debt and its management.” Journal of Systems and Software 101(2015): 193-220.

[7] “PEP 0008 – Style Guide for Python Code | Python.org.” 2014. 14 Oct. 2015<https://www.python.org/dev/peps/pep-0008/>

[8] Luo, Qingzhou et al. “An empirical analysis of flaky tests.” Proceedings of the22nd ACM SIGSOFT International Symposium on Foundations of Software En-gineering 16 Nov. 2014: 643-653.

[9] Ernst, Neil A et al. “Measure it? Manage it? Ignore it? software practitionersand technical debt.” Proceedings of the 2015 10th Joint Meeting on Foundationsof Software Engineering 30 Aug. 2015: 50-60.

[10] Shmerlin, Yulia, Doron Kliger, and Hayim Makabee. “Reducing technical debt:using persuasive technology for encouraging software developers to documentCode.” Advanced Information Systems Engineering Workshops 1 Jan. 2014: 207-212.

37

Page 47: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

BIBLIOGRAPHY

[11] Kernighan, Brian W, and Phillip James Plauger. “The elements of program-ming style.” The elements of programming style, by Kernighan, Brian W.;Plauger, PJ New York: McGraw-Hill, c1978. 1 (1978).

[12] “TIOBE Programming Community Index - TIOBE.com.” 2008. 20 Oct. 2015<http://www.tiobe.com/index.php/tiobe_index>

[13] “DjangoCon 2014- Inheriting a Sloppy Codebase ... - YouTube.” 2014. 20 Oct.2015 <http://www.youtube.com/watch?v=URztqq1kiqI>

[14] “How Disqus is using Django as the basis of our Service.” 2014.20 Oct. 2015 <http://pyvideo.org/video/2976/how-disqus-is-using-django-as-the-basis-of-our-se>

[15] Daniel Roy Greenfeld, and Audrey Roy Greenfeld. Two Scoops of Django: BestPractices for Django 1.8 Two Scoops Press 2015

[16] Marty Alchin. Pro Django 2nd Edition Apress, 2013

[17] Peter Baumgartner, and Yann Malet. High Performance Django CreateSpaceIndependent Publishing Platform 2015

[18] “DjangoCon 2008: Reusable Apps - YouTube.” 2008. 21 Oct. 2015 <http://www.youtube.com/watch?v=A-S0tqpPga4>

[19] “Fat Models - A Django Code Organization Strategy.” 2014. 3 Nov. 2015<http://redbeacon.github.io/2014/01/28/Fat-Models-a-Django-Code-Organization-Strategy/>

[20] Smith, Connie U, and Lloyd G Williams. “Software performance antipatterns.”Workshop on Software and Performance 17 Sep. 2000: 127-136.

[21] “Shortcomings in the Django ORM and a look at Peewee.” 2012.3 Nov. 2015 <http://charlesleifer.com/blog/shortcomings-in-the-django-orm-and-a-look-at-peewee-a-lightweight-alternative/>

[22] “Why I hate the Django ORM - YouTube.” 2012. 3 Nov. 2015 <http://www.youtube.com/watch?v=GxL9MnWlCwo>

[23] “A Di�erent View | Isotoma: Our blog.” 2015. 3 Nov. 2015 <https://www.isotoma.com/blog/2014/05/20/a-different-view/>

[24] “The Django template language | Django documentation ...” 2015. 4Nov. 2015 <https://docs.djangoproject.com/en/stable/ref/templates/language/>

[25] “Pylint features Pylint 1.5.0 documentation.” 2013. 2 Dec. 2015 <http://docs.pylint.org/features.html>

38

Page 48: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

BIBLIOGRAPHY

[26] “PyPI - the Python Package Index” 16 Jan. 2016 <https://pypi.python.org/pypi>

39

Page 49: Managing Technical Debt in Django Web Applicationskth.diva-portal.org/smash/get/diva2:946779/FULLTEXT01.pdf · 2016-07-05 · Django Web Applications PER CLASSON KTH ROYAL INSTITUTE

www.kth.se