Issues: bug, task, story and epic

taskboardBoth scrum and Kanban project boards allow for different issue types. In many tools for project boards, developers can even choose their own issue types. This page covers the standard scrum issue types, and particularly the differences between stories, tasks and epics.

Kanban and Scrum: What is the point?

Not as complex as many want you to believe

If you search for Kanban and Scrum on the net, the top results tend to be sponsored links pushing training, and products and presenting things as more complex than is necessary, so be aware of site professing things have to be a very specific way, when actually the key principles are quite simple.

An enhanced to-do list

The first basic principle is that of the to-do list.  Rather than drop what is being done at the time, to deal with a new idea or issue that arises and should not be ignored, add the new issue to the ‘to=do’ list or backlog, then finish the work in progress knowing the new issue will not be forgotten.  The goal of the backlog is to eliminate having to many work in progress tasks that are all being juggled thing to be done, and to avoid the loss of time from switching tasks to deal with new issues the moment they arise.

A backlog goes beyond a simple to-do list, because:

  • the ‘doers’ are not necessarily the same as those recording the issues
  • there can be a significant passage of time between recording and issue and the issue being addressed
  • the ‘to do’ list should allow for being agile and addressing the issue (or solving the problem) in a new way that may not have been obvious when the issue was recorded

The three points have significant impact that requires rethinking to-do lists.

Managed Workflow: Swim Lanes

There are three basic swim-lanes, the ‘to-do’, the ‘doing’ and the done.

The general principle is that issues move from left to right as they progress. Teams may add more columns reflecting more granularity of progress, and as an example, to clearly identify issues blocked by other issues.  There are alternative approaches for blocked issues and for most other concepts that can be addressed by additional lanes and  many teams find the three basic columns are the best.

Kanban vs Scrum: sprints

Various web sites will list many fine points of difference, but these are usually more between specific implementations of scrum and Kanban.  The basic difference is that scrum has sprints.  With sprints, a specific number of issues are moved from backlog to the project board with the goal of tackling these issues within a target timeframe.  Kanban is better suiting to dealing with work that arrives as a continuous flow and the backlog is simply and ordered ‘todo’ list.   With both Scrum and Kanban, that to-do list is impacted by the fact that the person recording the ‘to do’ may not be the same person as the person/team which will actually ‘do’ the ‘to do’.  Secondly, there is a need for agility so recording what to-do becomes less important than the reason something needs doing.  Kanban is usually implemented with limits to the size of one or more specific swim-lanes so that, for example, a maximum of five issues can be in the ‘doing‘/'in progress' swim-lane, blocking new issues from being started until the number already in-progress is reduced.

The Key to Agile: Stories vs Tasks

The concept of the story, and the difference from a task is central to agile development.

The question cans arise: “Is this a task or a story?” “What is the difference?”

The answer: Every issue has both a story and a task (or set of tasks)perpective. Story and task are as two sides of a coin.  The same thing seen from two different sides.

In simplistic terms, a task is what is to be done, and a story is why that task is to be done, or more specifically what the benefit of the task being complete will be. There are many different issue types used by various teams: bugs, tasks, stories, new features, enhancements… etc.  However all of these have the same two sides: seen as an story (what is the problem to be solved) or seen as a task (what is the solution). Regardless of the label of an issue, everything can be described by the problem (story) or the solution (task).

task viewpoint:

  • the solution
  • to be done
  • prescriptive

story viewpoint:

  • the problem, the requirement
  • the reason a task should be done
  • the why do it?
  • descriptive

Different Perspectives: Consider a non computing task, such as moving a filing cabinet from a corridor to another location because the filing cabinet restricts passage through the corridor and the corridor is being used as a fire exit.  The task is ‘move the filing cabinet’, the story is ‘the filing cabinet restricts the corridor which is being used as a fire exit’, or even ‘the corridor must be clear of obstructions as it is a fire exit’.  The temptation is to simply list what is to be done: the task.   Agile dictates, ‘no, list the story as an issue, with the task as a sub task’.  Why?  Because to be agile, the project needs to be open to more than one solution.  A key point is the issue goes to the backlog and will be tackled in the future when the best solution may have changed.  If it is months later, perhaps the corridor has already be widened? Perhaps the fire exit path has changed and no longer includes the corridor in question.  When it comes time deal with the issue, if it reads ‘move the filing cabinet’ the whole point of the move may no longer be apparent, or even valid.  Does the person with the task blindly follow the instructions at that time?

Bottom Line: Viewing issues from the story perspective is the key to agile.

Issue Size – How long is too long?

All issues to be scheduled in a sprint must first be have a time estimate to for completion that fits within the time allocated for the sprint.  If an issue is estimated to take longer than the maximum time that will fit in a sprint (see sprints, below) then perhaps consider the issue should be an epic, as Epics are not added to sprints.

Now imagine a sprint with one issue taking the entire sprint: not a great idea. Nothing could be marked as complete until the very end of the sprint, so no progress recorded. and zero feedback on how the sprint is progressing.   A further limitation is that it is very difficult to accurately estimate times beyond around two days.  A person can picture mentally how two days of time will actually be spent, but with a two week task, no one is picturing how each day of the of the two weeks will be spent.  The fact is, any estimate beyond around two days is just guesswork.  Over time, developers may get good at the guesswork, but within a sprint, it is best to drop the guess work and break down issues to sub-tasks such that no subtask will take more than two days of your time.

Story Points.

Estimating time for issues is problematic due to the fact that while project boards are like ‘to-do lists’,   the recorder of the issue, and ‘doer’ are not necessarily the same person/team, and time estimates depend on the view of the ‘doer’.

So issues should be placed in the backlog with an estimate of the size of the issue, rather than how long it will take.  So how do you record issue size?  Answer: Assign ‘Story points’ to each issue is the recognised best practice.

The requirement is that everyone working with the same project boards needs to have a common reference in order to measure issues in story points.   To do this, the first requirement is a scale, and the easiest to work with is a linear numeric scale, such that twice the complexity will double the number of story points.

The simplest possible story on the scale would be a ‘1’, double that complexity for a ‘2’ etc.  But what exactly does a ‘1’, a ‘2’ a ‘4’ or an ‘8’ look like in size?  The best way to cover this is a set of example.  Team members can add example to scale list, and with a review process that has recently tackled issues added as references:  “this was an 8, it involved these stages where the stages were (full explanation provided).  It needs at least 4 examples for the scale to be workable, but around 12 example (3 for each of 4 sizes) would be ideal.  New better examples could replace previous examples, once sufficient example are already documented.

Another discussion on story points can be found here.

The Issue Types

Tasks

A task is not really an issue type, but a way of describing an issue.  In fact, describing an issue as a task is the natural way to describe the issue.  A to-do list is naturally a list of tasks.  The reason for doing the task “goes without saying”.  Another occurrence of “what goes without saying” actually does need to be said, in part because what goes without saying today, no longer goes without saying several months later. The task needed doing is foremost in mind at the time of recording the issue, it can long be forgotten when the issue is to be addressed.  A different between ‘to do’ list and a backlog, is the possible long time delay between adding an issue and that issue being addressed from a backlog.

Another point is that it is exactly that which “goes without saying”, the very basics, that need to be questioned and examined when being agile.

All of these reasons are while describing an issue as a task is like looking at coin from one side. The task viewpoint is the best viewpoint for an individuals to-do list for the day, but the least important viewpoint for a backlog.  Adding an issue as a task should only happen when there is certainty the task will be addressed almost immediately.

For better results, always record the story viewpoint first, then add the task viewpoint. Or perhaps more realistically given how natural it is to first think of the task, first add the task as a sub-task to an empty story, then go back and add the story which at the time may feel so obvious it goes without saying.

Stories

The goal is to have stories for every issue, and record proposed solutions as sub-tasks for the story. This recording the story is examine the reason the task is to be done, and allow lateral thinking of alternative solutions, alternative tasks that could achieve the same goal.  The story is the essence of being agile.

Again, a ‘story’ is not really an issue type, but simply a way of thinking of an issue.  To address every issue there will be tasks to complete.

The art of good stories centres, on separating the solution and recording that in a sub task, and keeping the story about explaining what is the problem to be solved..

Bugs

A bug is actually an issue type.  The bug can be expressed in terms of the task to fix the bug, or preferably, the story of what the system fails to do correctly (the story).

Then main rule is that no attempt should be made to fix the bug before creating a unit test that fails due because of the bug.   With the failing test in place, and the test proven to fail while the bug is still present, it is relatively simple to then address the bug.  To record a bug, the obvious requirements are how to reproduce the bug, and what are the expected and actual behaviours.  Normally a bug will be added to either the current, or very next sprint, so what is recorded will be tackled soon, but it is still preferable to record the story and not just the task.

Features/Enhancements etc

These labels are again labels for a type of issue, each of which can again be described from task or story viewpoint. For agile development, the challenge is to become practiced in thinking in stories and ensuring the story is captured.

Epics

An epic is simply an issue to large to included in a single sprint, or with Kanban, tackled all at once. There are three strategies that I know for dealing with epics.

  1. The Epic Sprint Series. If story spans several sprints, then why not devote a series of sprints to that story? Making the Epic into a series of sprints means no specific issue for the Epic is needed, just a title to a series of sprints, and the stories of these sprints build the Epic.
  2. The Epic issue is an alternative for when the epic sprint series is of a very low priority, and there are many stories that will have higher priority, but it still matters to make a start on first stories of the epic.  In this rather specific situation, simply add the epic to the backlog as an issue type, and then design stories which together build the epic, but are each of a more workable size. Then add add each story to the backlog and tackle as with any other stories.
  3. The Composite Epic Sprint Series.  The Epic story may have other Epic stories or regular stories should be completed in parallel, and should not be delayed until the Epic is completed as an Epic Sprint Series.  The solution in this case is to first redefine to epic as a composite that included the original epic, and also the stories that should be completed in parallel. Then complete the new composite epic as an Epic Sprint Series.

Sprint Building

Building a sprint requires selecting issues from the backlog, assigning them to teams or individuals and estimating how those story points will convert to time for the teams assigned.  As issues can arise during a sprint, and new complexities revealed to the original issues, a buffer is required between estimated time the issues will take and time available.  A sound rule is to allow for the sprint taking anywhere from the original estimate, through to double the original estimate.  So sprint with tasks originally estimated at 2 weeks should be allocated from 2-4 weeks.

But which issues to choose?

The real art to a well build sprint is to ensure cohesion, which the issues fitting well together, and combining to a concrete goal for the entire sprint.   The challenge of a concrete goal, is that most worthwhile goals require more than one sprint.  Putting the concrete goal as the target of a single sprint risks a sprint that loses its way and takes months.

The best solution is to have the concrete goal for a series of sprints.  Make the goals into what is effectively an epic, but do not create the epic as an issue, but as the goal of a series of sprints. Just as discussed in epics, as an epic sprint series.

Further reading:
Some notes on project plans.
Advertisements

Gradle Kotlin DSL 1.0: Basic App Build

Contents:

  • Kotlin DSL list of other pages
  • Build Basics in Gradle
    • Plugins
    • Dependencies and Artifact Repositories
  • A Simple Practical Example
  • Varying the Source Locations: SourceSets
  • Application
  • Testing – JUnit
  • local jars as dependencies

Continue reading “Gradle Kotlin DSL 1.0: Basic App Build”

Interfaces, Delegation & Composition vs Multiple Inheritance & Duck Typing

Kotlin has Interface, Abstract Classes and Delegation, while Python has multiple inheritance. Different tools, same problems.  The different tools reflect an evolution of what Object Oriented best summed up by: Composition over inheritance. The rethink, the new concepts and how to use them are explained here.

Abstract Classes.

With Koltin, Interfaces can do almost all that abstract classes can do, and the reverse is not true.  So why learn two things instead of one, when only one you need is interfaces?  Answer: Don’t bother learning abstract classes until experienced with every other topic here.  For more this answer to ‘why use abstract classes vs interfaces‘ from stackoverflow is useful in three ways:

  1. it highlights that it is not obvious why use and abstract class when in almost all cases an interface is preferred
  2. the answers on stack overflow are all related to rather unusual cases where even  with Kotlin, there some benefit from the use of an abstract class over an interface
  3. it makes the point that interfaces in Kotlin are more powerful than in other languages, making abstract classes largely unnecessary

Consider the above points.  Don’t bother with abstract classes unless coverting java code that has interfaces.  In languages such a java, the less powerful interfaces create more use for abstract classes, but they are mostly outdated by more powerful interfaces.

Interfaces: Better Duck Typing

Polymorphism is one of the four basic pillars of Object Oriented Programming, and inheritance is a key tool to deliver polymorphism. Interfaces provide an alternative way to deliver polymorphism, and are more in keeping with duck typing.

Inheritance is based on the idea that the new class is a type of the old class. While an interface lists what the two classes can both do.  The Wikipedia pages  a Is-a and Has-a discuss the concepts at considerable length, and provide a lot of further reading if desired.

Consider the example started in the polymorphism section and continued in the inheritance section  with Animals objects. The Animals then subclassed to Duck objects and Dog objects, with Ducks then again subclassed to specific Duck types.  In the example, the base Class Animal has ‘talk()‘ and ‘move()‘ methods, and a ‘size‘ property.  ‘Animal' is a common choice as example for inheritance, this example can also be coded using an interface.  We can even leave the methods of the interface empty, as in reality, the base Class ‘Animal‘ cannot really have a meaningful value for ‘size‘ or meaningful methods of move and talk that are useful for all Animals, or in this case, for both dog and duck.  With an interface, there is the choice with every attribute to provide a default, or to leave the implementation empty, which forces code using the interface to provide an implementation.

Now a Duck is an Animal, so passes the ‘Is A’ test. But we can still choose to take the interface approach, and simply say a duck has all of  ‘talk()‘, ‘move()' and ‘size()‘.  By thinking this way, and only declaring that an object need have these attributes whether on not actually an animal, it allows any object that can have these attributes to effectively be an animal for the purposes of our code.  If I have robot vacuum that can move, makes sound (talk) and has size, I can manipulate it with code designed to work with our animal class.

So instead of a Base class, define an interface, that any animal must implement talk, move and have size. If it can talk like an Animal, and move like an Animal, then we can consider it an Animal.


interface Animal{
   var size:Int
   fun move(speed: Int) //functions can have code if desired
   fun talk(howLoud: Int)
}

interface StillAnimal: Animal{
   override fun move(speed: Int) {
   }  // declare code as empty code... no response to move
}

If I declare a Class implements the Animal interface, then I will immediately get an error if I forget to add one of the attributes specified by the interface.  The fact is that the code doesn’t care if the an object is actually an animal, as long as the object implements size, move and talk.  If fact, this the central premise of Duck Typing in python, that if an object has the attributes required by a block of code, the actual Type doesn’t matter, from the perspective of that block of code, the object is needed type.  If the object is asked to do something, and the object responds the right way, then it doesn’t matter what the actual type is for the object.

The challenge with python, is that the only way to see if the object does have the needed attributes, and these attributes are as required (like the base class or interface) and thus they accept the correct parameters etc, is to perform a a significant number tests, or more typically, simply ‘try', and handle errors with an ‘except' if necessary.

In Kotlin, Duck Typing becomes be far easier.  Just declare that a parameter with an ‘interface' as the, in this case the Animal interface, and then any object of any type that implements the animal interface will be accepted as a parameter.  Then, no tests are required at run time, as the needed attributes are known to be present and correct. This is the goal of Duck Typing, made simpler and cleaner by Kotlin.

Multiple Interfaces vs Multiple Inheritance

Consider that a that some code requires animals that have specific set of additional attributes.  If animal objects are 3D objects within a game, perhaps part of the system wants Animals with expressions. In Python, we could have an Expressions class which could have smile() and frown() methods, the we can make objects that inherit from both Animal and Expressions.  In Kotlin, Expressions would be an interface so we could have an object which inherits from Animal and implements the Expression interface, or implements both Animal and Expression interfaces, but cannot inherit two parent objects.  Why not?  I mean, as people, we inherit from two parents, don’t we? However both ‘Parents’ are Humans, subclassed to Male and Female, where both sub classes have many attributes in common.  The reality is while we inherit from two parents, there is a lot of overlap between these two classes, and we may want to access a little of each from those overlaps.  So Object Inheritance does not deliver the model of inheritance in nature.   This same problem of duplicate attributes, gets more complex with objects inheriting from multiple parent objects.  Inheritance implementations require a strategy to ensure only one of each potential duplicate is inherited, but typically this means giving priority to one parent.  No fathers eyes, and mothers smile… there is one priority for every duplicated attribute.  The fact that this does not always work is specifically recognises with the Python init() which will try to run the init() of both parents with super(), and it gets complex.    Articles on multiple inheritance in Python get into the MRO and how to handle the duplications.  Replacing multiple inheritance of Classes, with multiple inheritance of interfaces allows easier eliminating sources of duplication at the outset, as in interface has only the elements specifically designed to be inherited, no constructors or methods not specifically nominated to be in the interface.  But moving to interfaces does not solve everything. What if you still want not just an interface, but an object the implements the interface of each parent?

Composition over inheritance.

Composition, rather than inheritance is seen as the ideal solution when a complete implementations  of multiple objects is required. Composition means the new object will contain an instance of both ‘parent’ object, rather than inherit from both parents.  The object ‘composed’ is then in full control to select attributes from either or both parents.

Consider a case where we desire the behaviour of a Duck object (where a Duck is a Class that inherits from Animal)  and also require the behaviour an Expression object.

Inheritance: With Python, the data to instance our desired Duck and desired Expression can be passed to the our new object, which inherits from both Classes. In the init() method of our new class, the data to init each of the two parents has been passed in the constructor, so we have the data to init each  parent.

Basic Composition(worst case): We could, rather than call init() for each parent, not use inheritance at all but use the data we would pass to init() the create a new object each type.

#inheritance
class ExpressiveDuck(Duck, Expression):
   def __init__(self, duck_data, express_data):
      # note super()__init__() does not work, if parent init has data
      Duck.__init__(self, duck_data)
      Expression.__init__(self, express_data)

#attempt at composition
class ExpressiveDuck:
    def __init__(self, duck_data, express_data):
        self.duck = Duck(duck_data)
        self.express = Expression(express_data)
   @property
   def size(self):
       return self.duck.size
   def move(self, speed):
       return self.duck.move(speed)
   def smile(self, howHappy):
       return self.express.smile(howHappy)

The example for composition actually needs even two more methods, but they were omitted just to save space.  It is already clear that in this case, with python, composition requires significantly more code.   Despite all the questions and agonising, even the init() method for the inheritance example can be clear if you avoid super() , at least for parents where the init() has parameters…. and init methods will nearly always need parameters in the real world.

Init() is the only complexity in this inheritance example, because it is the only attribute that is in both parents.  No duplicated attributes makes this a example a best case for inheritance, and a worst case example for composition with python.  However, as we will see, there are still reasons to have composition, and in Kotlin, even this example no longer need be considered a ‘worst case’.

Dependency Injection.

In the previous Composition over Inheritance example,  Duck and Expression become the dependencies for the class ExpressiveDuck.  Whether using Inheritance or Composition, ExpressiveDuck depends on Duck and Expression classes. Now here is an example in Kotlin just to demonstrate the move to allow dependency injection, while still allowing compatibility with that previous example.

// note... this is the long way to do this!
class ExpressiveDuck(var duck:Duck, var expression: Expression)
      : Animal, Expression // announce both interfaces will be delivered!
      // note 'Duck' is an implementation of the Animal Interface
          {
      constructor(duckData: DuckData, expressData: ExpressData)
          :this( Duck(duckData), Expression(expressData)
     // now delegate the attributes as needed
     override val size get() = duck.data
     override fun move(speed) = duck.move(speed)
     override fun talk(howLoud) = duck.talk(howLoud)
     override fun smile(howHappy) = express.smile(howHappy)
     override fun frown(howMad) = express.frown(howMad)
}

This new ExpressiveDuck has a primary constructor that accepts the two objects that it ‘inherits’ from.  This means there is now a constructor that could work for any object that implements the Duck and Expression interfaces.  No need to create a whole family of Classes for different parent Classes, the parent class can now be supplied as a parameter.  In fact, we no longer need an ExpressiveDuck class at all, and the same code will work as ExpressiveAnimal.  Since the Duck class is a specific implementation (sub subclass) of Animal, with the same interface as Animal, our class will make an expressive ‘any animal we like as long as you pass one of those animals as a parameter’.

Further, the generic nature of having the parent class as a parameter means we could be passed a special subclass that simply adds checking whenever move is called,  of completely mocks the Expression object to allow better unit tests.

If only it wasn’t for those pesky delegations(too much boilerplate to type)!

Note: As many examples, this one is somewhat contrived.  Duck would probably be a class that implements the Animal interface, so if we went back to the original idea of just a ExpressiveDuck, then we could inherit from Duck and the above example using only using the above features would be simpler.  Ok, but not as flexible, and it turns out we can make this solution even better.

Kotlin Class Delegates: Automated Delegation.

In fact Kotlin does address those ‘pesky delegations’. Called ‘Class Delegates’, instead of just listing the interfaces a class is declaring will implemented, it can also delegate the implementation to an object, just as we did manually in the previous example.

// note... now the Kotlin way!!
class ExpressiveDuck(var animal:Animal, var expression: Expression)
           : Animal by animal, Expression by expression { // delegated!

    constructor(duckData: DuckData, expressData: ExpressData)
          :this( Duck(duckData), Expression(expressData)
   // all delegates are automatic!

So now the code is as concise as the Python inheritance example, even for this worst case for using construction.  Not only is the code as concise as the Python code, it is far more functional, still supporting the same specific case with the same interface (when called with duckData and expressData) but removing the need for a whole family of classes by working with  Animal or any Expression implementation,  and even supporting mocking for testing.

Note, explicit overrides are still required where an attribute is duplicated within the delegate interfaces. However the IDE will alert the developer, rather than needing to detect unexpected behaviour at run time.

Summary

The combination of Interfaces and Class Delegates allows for an improved solution to multiple inheritance, that can provide dependency injection with no additional overhead.

 

 

Kotlin? Or another alternative?

The theme for these pages is on learning Kotlin with Python as the starting point. Python is applicable desktop/server applications, as is every language on this page.  However some also deliver: Native Code, Browser Code, Mobile Apps and JVM applications.

Is Kotlin the best choice to compliment Python? Kotlin rates very highly on ‘liked scales’ and ticks all the bases Python does not, but often not all bases need be covered.  This page considers the alternatives.

Generally, the main languages to consider are languages actually liked by programmers, then consider rating in a popularity ranking such as Pypl, then filter for those that can be used for potential your needs, particularly if they can be used when python cannot.

  • C/C++
  • C#
  • Java
  • Javascript
  • Typescript
  • Ruby
  • Scala
  • Go
  • PHP
  • Swift
  • Rust

C/C++

It seems like C has been the only real choice to produce native code for almost forever. At least until recently with Kotlin, Go and Rust as better choices to get write an application in native code.  There are still niches where C/C++ is still the only choice available, but more significantly, no other language (beyond assembler) forces you to understand the internals of a computer to the level as C.  Ideally everyone should learn C/C++, but no one should have to be effective as a programmer using C/C++.  (Native, but no JVM, no browser code, no mobile app support),

Java

I think Java is ranked as at least #3 in almost every language popularity/usage ranking, but every ranking is also showing declining use of Java.  In reality Koltin is clearly a more liked language, and one that can do everything that Java can.  The only reasons to consider Java are: 1) to get job, 2) there is some reason that even the Java compatibility offered by Kotlin is simply not enough. (JVM, android Mobile, limited browser, no real native support, no IOS support).

Ruby.

I mean a language designed to make programmers happy? What could go wrong? Well, the main thing that could go wrong is that programmers are happier with other languages, like Kotlin, or Python.  So the main is missed unless coming from Java or C or something. Coming from Python, it is similar class of language that meets only the same needs, but with less popularity and less liked by developers. (no browser, no mobile, no native, no JVM)

PHP.

Please….just don’t go there.  There is a reason this is the fastest declining language on pypl. (no browser, no mobile, no native, no JVM)

more updates to follow…..

Glossary

Some meanings here are genuinely in ‘universal’ use (the universe being limited geographically to Earth).  However, ‘universal’ agreement is extremely rare.  So very often this is about the definition I have chosen to work with.   In fact, in some cases, there are at least two common uses of the same term. These also make the glossary.  We are not arguing for universal use in the way we use the term, but we do have a need for a specific term matching the definition here, so one these pages, and in our team, this is what the term is taken to mean.  This is of course open to debate and refinement.

Attribute:  Every thing that can be accessed using ‘.’ notion within an object.  This includes fields, properties, methods, and sometimes even functions.

Computing: Hopefully self explanatory, but aslo used as a substitute for IT when used in the more general sense, as opposed to the narrower more specifc use of IT as in this glossary.

Field: An attribute which holds data.

Information Technology (see IT)

IT. There are two very different interpretations of IT.  Wikipedia describes Information Technology in the more general sense, then adds “often in the context of a business or other enterprise”, effectively covering both the wider meaning, and the more specific meaning.  With no other term for the more specific meaning, we use Computing for the use without the ‘often’ and use IT for ‘only when the often applies’. To clarify:

Information Tecnology(IT): the use of computers to store, retrieve, transmit, and manipulate data, or information, in the context of a business or other enterprise, for use within that business or other enterprise

Property: An attribute which holds data and can be accessed from code external to the class through either explicit or implicit get and optionally  set methods. Python does generally use the term property only when explicit get and set are in use, but as only Kotlin has obvious implicit get and set for all fields accessed outside a class, then the term works for both languages with this definition.

TTD: Test driven development. A discipline where developers create tests  first and never code except to pass a failing test. At the extreme, it is suggested that system design should only be arise from coding to pass tests.

Unit Test: Broader meaning: Any fully automated test driven by a test module such as pytest or junit.  Narrower Meaning: Tests as per the broader meaning which are reliant only on the specific class or ‘unit’ under test, with all other systems fully mocked. Under this narrower meaning, any tests that rely on other component rather than a mock, are integration tests.