There are a few techniques to make code more reliable:

Contracts

It is a set of pre and postconditions attached to functions or types, which can be functions themselves. They might be enforced both at compile and execution time, or by external tools against the code See: ADA implementation

Type system

The programming language forces the programmer to specify types. The compiler enforces the coherency of the types. Types are connected by inheritance and composittion. Aspects can be specified via interfaces too.

Haskell excels at this.

Tests

It is a set of functions that are executed indepently of the execution

Unit

Individual units, modules or functions of the program are tested. They are specially effective for side-effect free functions and well designed code.

def mean(iterable):
    return sum(iterable)/len(iterable)

class ModuleTestCase(unittest.TestCase)
    def test_for_mean():
        self.assertEqual(mean(range(3)), 1)
        self.assertRaises(ZeroDivisionError, mean, [])
    

Behaviour/Case

Domain behaviours are tested. Behaviour driven delveopment uses this as a premise as well. It uses a DSL specifically designed for the purpose of testing.

The idea is to test bigger sections of the code that follow certaing begaviours associated with the Domain.

Formal proof

Proving correctness of the algorithm with some mathematical framework. Formal proof is easier to do in functional languages due to their closeness to Algebra.

Abstraction

The quality of the code relies on the structure of it. A better structure implies less code or more robusts on most scenarios

Domain

Making the code closer to the domain means that there is less chance for implicit concepts or unexpected behaviour. Domain Driven design is a set of techniques to achieve this purpose

DSL


It involves the creation of new languages to deal with specific parts of the domain. It could be an internal or an external DSL