Saturday 21 January 2023

Automated Tests.

Application Design & Use Cases.

Often, when a customer orders application, she or he orders a collection of a certain functionalities.

For example:
- logging into online email application,
- deleting all spam in spam inbox,
- logging off automatically after a given time,
- configuring email sorting preferences,
- ...

Use cases are means of specifying these functionalities, defined by a number of steps (click here, scroll here, type something here, read report's field #n, etc ...).

A minimal set of use cases often determines how user interface should look, is often a formal requirement for ordered application functionalities - can be a part of the business contract between a customer & a developer company.


Automated Tests, Changes & Debugging.

Often tests for use cases can be automated, can be performed after any change is introduced into the code ... just before program's compilation, just before running an application, or at any other convenient moment.

By using Automated Use Case Tests, programmers can be comfortable that when they (or their teammates) change parts of the code, the older parts of the code (previous functionalities) that they are responsible for - won't prove erroneous after the new code additions.

Automated Use Case tests often show when part of the code is erroneous after changes, and while these are far from being 'proofs of code's correctness', these are extremely practical nevertheless. Even if not every error is caught by these - carefully designed tests can quickly find basic functionality failures. Other errors can still be found & fixed using other methods, and it's still easier to fix one error than multiple overlapping ones.

More than that - carefully designed automated tests can help programmer to create 'Mental Test Harness' that let's them more boldly & quickly do larger changes in code without inspecting the same things over & over, without fearing of application breakages so much.

This also builds Trust & Responsibility in the teams - with tests it's quick & easy to find out when someone breaks other teammate's code parts - at early stage of failure at that, so it can be addressed before error turns to be too complex to address quickly, before true stress, psychological dramas & employee firings start, before project's budgets & time schedules are endangered.

In many ways, Automated Tests help to develop applications with much more of the speed & security, with only a small amount of extra code at start (tests have to be designed & written too) & with a small amount of maintenance (when requirements change, tests have to be modified).


Documentation & Automated Tests.

Important aspect of code's quality are automated tests and documentation.

Developers should not write in documentation anything they please, there should be formal standards on what to write and how.

Class documentation should state the Contract between class user and class creator - class responsibility, invariants, what results code provides on which conditions. Results are not only returned values of methods, but also exceptions thrown, state changes, methods called and events raised.

As of how classes should be documented - there's for example Javadoc writing guidelines and requirements, these are about style, keywords and syntax.


Automated Tests for each of classes should be grouped in a single file.

Within that file many tests can be provided, one or more tests for each of tested class' methods.

Tests should check if documented contracts are intact, should check every of 'border criteria'.

Tests can also be written for software's use cases.

... for Java's automated testing tools, check, if You wish:
- JUnit 5,
- EasyMock.


See also: Software Development & Quality.

Contracts.

Introduction.

Design by Contract is the Software Collaboration Method.

Contract / between class user and class author / should state under which condition class will provide it's services to class user, and what these services are.


Contract.

There are Preconditions, Postconditions and Invariants that regulate contract.

Precondition is a condition that is required for something to happen. Precondition can be simple or complex, complex precondition consists of multiple simple or complex preconditions as well.

Postcondition is something that is guaranteed to happen if preconditions are met & program behaves correctly.

Invariants is something that is guaranteed to hold, at least in observable moments in time, or perhaps even all the time.


If class user provides 'correct' / or using alternative wording: 'legal' / preconditions to object, methods will ensure that postconditions are met.

Invariants are always met / though some disagree, for there's 'observable moment' argument /, or contract is broken.


Examples for Preconditions:

- requirements for method arguments allowed values,
- concurrency requirements,
- perhaps more.


Examples for Postconditions:

- program's process(-es) will compute and provide results correctly,
- program will finish within the agreed time frame in at least 90% of situations,
- perhaps more.


Examples for Invariants:

- heat in Reactor will never go above the Critical Value,
- variable 'divisor' will never have '0' value,
- variable 'divisor' will never have '0' value during computations phase,
- perhaps more.


Inheritance / in simple words /.

To not break contract, following conditions must be met:

1. subclasses must require no more than it's neccessary for superclass to work correctly / but can require less /.

2. subclasses must meet all requirements of superclass / but perhaps can give more /.

This is related with the Liskov's Substitution Principle / LSP /.


Exceptions in Java.

When contract is broken during Runtime, an Exception should be thrown.


Friday 20 January 2023

A few thoughts on code quality - mostly for Java, but can be abstracted and used with different technologies.

In my opinion java code of quality should have following properties:

1. Proper naming of classess, methods, variables and constants.
2. Single, properly defined and documented responsibility of each class and method. No unneccessary code (to remove code duplication you can use constants (final keyword, UPPERCASE_NAMES) and split methods with large chunks of code into few smaller methods so you can reuse them. To ensure single responsibility of method or class move some code into another method or class. Single responsibility class or method is more reausable and easier to document, read, test and modify. [or to break if someone wants to try firing quality coder].). Single responsibility of method may involve calling more than one instruction as long as it is considered atomic. For example: changeStateWithSideEffect(...);
3. Documented methods headers (first lines of methods and all information therein, including variable names) according to javadoc documentation.
4. Use of 'assert' keyword, software contracts, preconditions, postconditions and invariants.
5. Fitting 'a complete code part' on a 'single screen', if possible and worthwhile; ... easier thinking, less scrolling, perhaps more.

Later JUnit/Easymock automated tests can be added to build test harness.

Also, code should be properly formatted.

Commits / to code repository, using technologies such as SVN or Git / should be commented.

Methods should be abstract, empty or final.

Ideally, methods should consists of three instructions. init(...); transform(...); return [(...)]; Complex instruction counts as single instruction;

There can be more requirements / for example: coding in idiomatic way / , but in practice it's almost perfect if these are used. Professionals after all have no time to comment code, or they want to be priceless and unfirable by bosses, in a not-so-nice, unfair way.


See also: Design by Contract.