Blog-Archiv

Sonntag, 29. April 2018

Getting Used to TypeScript, Part 2

TypeScript is a programming language with a lot of possibilities and freedom. I won't discuss it in detail completely here in my Blog, it's too big, I will just present some findings from time to time.

In this Blog I tried to continue my recent implementations in an object-oriented way:

  • Separate interface abstractions from concrete implementations
  • Extend and reuse existing interfaces and classes to facilitate easy maintenance
  • Minimize code duplications through inheritance (DRY)
  • Keep everything strictly typed to find mistakes already at compile-time
  • Use access modifiers (private, protected) to minimize the risk of abuse and encapsulate complexity
  • Prefer constants to variables, and immutable objects (readonly properties) to mutable ones

About Interfaces

Why are interfaces important? Because they represent partial aspects of things. Using such abstractions you can reduce the dependencies among your classes. For example, if you use a type Duck, and you need it just for swimming, not quacking or anything else a duck does, then you should pass the duck as interface Swimmer into your module. Later on the Duck may be replaced by a Swan, but your code doesn't need not to be maintained, because a swan is a Swimmer too!

Interfaces are roles, class-objects are actors. If you want to choose between different actors for a role in your drama, then create an interface for that role.

Remember CRC cards, one of the earliest OO software design methods: Class-Responsibility-Collaboration. Responsibilities can be covered by roles better than by actors. If you organize the work in your company in terms of well-described roles, and a certain colleague that always performed a critical responsibility gets ill, then someone that knows how to implement that role can take over.

You don't need to create an interface for every concrete class. Use them wherever it is necessary (or useful) to have partial abstractions (stick to YAGNI). When you can (or must) provide default implementations, use abstract classes instead.

The concept of interfaces had been introduced by Java, although there were predecessors like the C header files. Java interfaces always played an important design role. Lots of Sun specifications were done by providing just interfaces. While durable implementations were developed, simple reference implementations were available for those that already used the interfaces in their applications. Interfaces are a way to standardize problem solutions without anticipating which the best solution will actually be (fastest? safest? smallest?).

For C programmers: if you search for a possibility to implement function-pointers in Java, use interfaces, they come closest to it, and, other than in C, they are fully typed.


Rectangle 3D = Box

Here, in these "Getting used to TypeScript" Blogs, I use interfaces just to try out their capabilities.

Following examples build on the interfaces and classes that I introduced in my recent Blog about TypeScript. There were interfaces Dimension, Point and Rectangle, and their according implementations DimensionImpl, PointImpl and RectangleImpl. The new source extends them to be 3-dimensional, i.e. Point gets a z coordinate, Dimension a length, and Rectangle turns into Box. Here is the extended UML class diagram:

Source Code

I had to adapt the old source of PointImpl to make private methods available as protected. A standard activity when you want to reuse some source code.

export class PointImpl implements Point
{    
    ....

    protected distanceX(other: Point): number    {
        return this.x - other.x;
    }
    protected distanceY(other: Point): number    {
        return this.y - other.y;
    }
}

These methods are needed in Point3DImpl that extends PointImpl.


I've put the new sources into a directory 3D below the old ones. You can see that through the import statements.

Update: CAUTION, the following class design is not completely clean. Compiler options uncovered a function overloading mistake (that I fixed in another Blog): you can not overwrite Point.distance(other?: Point) in PointImpl with distance(other?: Point3D) in Point3DImpl.

Interfaces
Dimension3D.ts
import { Dimension } from "../Dimension.js";

export interface Dimension3D extends Dimension
{
    readonly length: number;
    volume(): number;
}
Point3D.ts
import { Point } from "../Point.js";

export interface Point3D extends Point
{
    readonly z: number;
}
Box.ts
import { Point3D } from "./Point3D.js";
import { Dimension3D } from "./Dimension3D.js";

export interface Box extends Point3D, Dimension3D
{
    move(origin: Point3D): Box;
    resize(newDimension: Dimension3D): Box;
}
Classes
Dimension3DImpl.ts
import { DimensionImpl } from "../DimensionImpl.js";
import { Dimension3D } from "./Dimension3D.js";

export class Dimension3DImpl extends DimensionImpl implements Dimension3D
{
    readonly length: number;

    constructor(width: number, height: number, length: number)    {
        super(width, height);
        
        this.length = length;
    }
    
    volume(): number    {
        return this.area() * this.length;
    }
}
Point3DImpl.ts
import { Point3D } from "./Point3D.js";
import { PointImpl } from "../PointImpl.js";

export class Point3DImpl extends PointImpl implements Point3D
{
    readonly z: number;
 
    constructor(x: number, y: number, z: number)    {
        super(x, y);
        
        this.z = z;
    }

    distance(other?: Point3D): number    {
        if ( ! other )
            other = new Point3DImpl(0, 0, 0);
            
        const distanceX = this.distanceX(other);
        const distanceY = this.distanceY(other);
        const distanceZ = this.distanceZ(other);
        return Math.sqrt(distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ);
    }
    
    transform(origin: Point3D): Point3D    {
        return new Point3DImpl(this.distanceX(origin), this.distanceY(origin), this.distanceZ(origin));
    }

    private distanceZ(other: Point3D): number    {
        return this.z - other.z;
    }
}
BoxImpl.ts
import { Point3D } from "./Point3D.js";
import { Point3DImpl } from "./Point3DImpl.js";
import { Dimension3D } from "./Dimension3D.js";
import { Box } from "./Box.js";

export class BoxImpl extends Point3DImpl implements Box
{
    private readonly dimension: Dimension3D;
    readonly width: number;
    readonly height: number;
    readonly length: number;
    
    constructor(origin: Point3D, dimension: Dimension3D)    {
        super(origin.x, origin.y, origin.z);
        
        this.dimension = dimension;
        this.width = dimension.width;
        this.height = dimension.height;
        this.length = dimension.length;
    }
    
    volume(): number    {
        return this.dimension.volume();
    }
    area(): number    {
        return this.dimension.area();
    }
    
    resize(newDimension: Dimension3D): Box    {
        return new BoxImpl(this, newDimension);
    }
    move(newOrigin: Point3D): Box    {
        return new BoxImpl(newOrigin, this.dimension);
    }
}

Mind the fact that I needed to duplicate the Dimension3D properties width, height and length into BoxImpl. This is due to single inheritance, BoxImpl extends Point3DImpl, thus it must hold a delegate to also implement Dimension3D. But it can not forward to the dimension-properties! As a consequence, the property values are held twice. In case these properties were not immutable (readonly) this would be a real hazard, because the forwarded methods volume() and area() work on the dimension delegate, while redundant values, implementing Dimension3D, are stored in the BoxImpl instance.

This has been more cleanly solved in Java, where interface fields always are constants, not even settable by a constructor. Java interfaces contain just constants and methods. No delegate-forwarding problem.

Java 8 interfaces now can contain also default method implementations. There is nothing similar in TypeScript. If you look at the files that are generated from TypeScript interfaces, you will find them empty. They are used just for compilation. But TypeScript supports abstract classes, which is somehow similar.


Conclusion

In my next Blog I will add tests to prove that the implementations actually work.




Mittwoch, 25. April 2018

Personal Encrypted Communication with OpenSSL

This topic has been explained on many sites on the web. I am neither a cryptography expert nor do I like this kind of things, but the need for it is increasing. Imagine you want to send someone your bank account ID. Would you do this on communication tools like Slack, Hangout, Skype, ... or by e-mail? For sure not, these mediums are not secure. But if you protect your communication, you can use any of them!

Prerequisites

  • Download and install OpenSSL, this is an open source command-line utility (SSL = secure socket layer, used by browsers); on LINUX machines it is mostly already present

  • You can send binary files to your communication partners, and they can send to you

  • You know how to work with terminal windows, command utilities, files and directories

The Public Private Key Method

This method relies on the fact that you never give away your private key to anyone. Persons that want to send you an encrypted message need a public key generated from your private key. Send a public key to them, you can use any medium that allows file attachments. Decrypt the messages they send to you with your private key.

If you want to send an encrypted message to someone, you need the public key of this person (not its private!). The public key of your partner is for your encryption, your own private key is for decryption of your partner's messages. Never use your own public key for anything else than sending it to communication partners.

It is not possible to find out a private key from one of its public keys. This makes it impossible for anyone else to decrypt the messages sent to you, encrypted by one of your public keys. Not even the sender will be able to decrypt it. That's the reason why it is called "asymmetric" cryptography.

Generate a Private Key

Create a directory on your machine where you keep your private key. Then open a command terminal window and change into that directory. Being there, enter following command:

openssl genrsa -out rsa_private.pem 2048

This command creates a file rsa_private.pem that contains an unencrypted private RSA key. You won't need a password when using this key. PEM is a format that uses just ASCII characters ("Privacy Enhanced Mail").

Alternatively:

openssl genrsa -des3 -out rsa_private.pem 2048

This creates a private key encrypted with DES3 cipher. On creation of this key you will be asked for a password. Any time you use the key in file rsa_private.pem, openssl will ask you interactively for this password. Good privacy, but you must remember the password.

It is recommendable to save your private key to a (password-protected) USB stick, in case your machine crashes and you still need the key for decrypting messages sent to you.

Generate a Public Key

You can generate new public keys at any time from your private key (that you may generate just once).

openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem

The public key will be in file rsa_public.pem after.

Encrypt with a Public Key

Mind that only short texts up to 245 bytes can be encrypted with a public key like generated here. Put some lines of text into file cleartext.txt, and then run this command:

openssl rsautl -encrypt -inkey rsa_public.pem -pubin -in cleartext.txt -out encryptedtext.bin

cleartext.txt will have been written encrypted to file encryptedtext.bin. Mind that this file does not contain readable ASCII characters.

Decrypt with your Private Key

You received a (short) encrypted file encryptedtext.bin.

openssl rsautl -decrypt -inkey rsa_private.pem -in encryptedtext.bin -out decrypted.txt

# diff decrypted.txt cleartext.txt || echo "THIS WENT WRONG!"

Having done this, decryptedtext.txt will contain what was in cleartext.txt on the sender side.


Sending Long Files

For trying out this, put some more text into file cleartext.txt.

Because we can encrypt just short texts up to 245 bytes with our public key, we need another technique for longer files. We will encrypt the file with AES algorithm and a randomly generated key. This key is called "symmetric" key, because your communication partner will need it also for decryption. But you can send it along with the data, it will be encrypted using the public key of the receiver.

Create a Random Key

openssl rand -base64 32 >randomkey.txt

A new unencrypted symmetric key now resides in file randomkey.txt.

Encrypt the Random Key with Public Key

openssl rsautl -encrypt -inkey rsa_public.pem -pubin -in randomkey.txt -out randomkey_encrypted.bin

Do this with the public key of your communication partner. File randomkey_encrypted.bin is now the encrypted symmetric key, ready to be sent along with the data.

Encrypt the Data with Random Key

openssl enc -aes-256-cbc -salt -in cleartext.txt -out encryptedtext.bin -pass file:./randomkey.txt

The text that you want to send must be encrypted using the unencrypted symmetric key. Your data in encryptedtext.bin is now encrypted and ready to be sent, along with the encrypted symmetric key.

What to send now:

  1. encryptedtext.bin
  2. randomkey_encrypted.bin

Receiving Long Files

You received two files. One must be identifiable as the encrypted symmetric key, the other holds the data to be decrypted. Lets say they were:

  1. encryptedtext.bin
  2. randomkey_encrypted.bin

Decrypt the Random Key with Private Key

openssl rsautl -decrypt -inkey rsa_private.pem -in randomkey_encrypted.bin -out randomkey.txt

The decrypted symmetric random key is now in file randomkey.txt.

Decrypt the Data with Random Key

openssl enc -d -aes-256-cbc -in encryptedtext.bin -out decrypted.txt -pass file:./randomkey.txt 

That's it, the decrypted data is now in decrypted.txt.



Conclusion

Definitely too cryptic to keep in mind all these parameters:-) Keep it in a Blog.

Latest achievement in cryptography is ECDSA ("Elliptic Curve DSA"). OpenSSL already supports it.

Use secure messengers like Signal, Wire, or Threema.




Sonntag, 22. April 2018

Getting Used to TypeScript, Part 1

TypeScript is, like its base-languages ES6 and JavaScript, a very flexible language. You can express things in many different ways. This provides great freedom for developers that write new source code, but lots of efforts for those that have to read and understand it on maintenance. In that way, TypeScript reminds me a little bit of Scala, although it (fortunately) has no operator overloading. Programming languages that allow so much freedom of expression are sure not made for common sense. Mind that common sense is one of the main goals of Scrum!

I am a Java developer. For this Blog I tried to implement the interfaces and classes Point, Dimension and Rectangle in TypeScript, separating interfaces and implementations in an OO way. Following are my findings when thinking in Java but implementing in TypeScript. Both support interfaces and classes. Both support only single inheritance in classes, but multiple inheritance in interfaces.

Type Assignments

They go after the variable or parameter name. It is not

Point origin;  // Java

In TypeScript (and all newer programming languages like Scala or Kotlin) this has become

origin: Point;  // TypeScript

So the type of the field goes after the name, separated by a colon. This applies also to functions:

function foobar(foo: string, bar: number): boolean {
    return true;
}

For standalone functions (outside any class) you need the function keyword. Inside classes you must drop it.

Members Always Need this

It was called "member" in C++, and "field" in Java. I am talking about width and height in following TypeScript class:

class DimensionImpl
{
    width: number;
    height: number;

    ....

    area(): number {
        return this.width * this.height;
    }
}

Look at the area() implementation, and how class fields are accessed. Other than in Java there is no implicit "this". You always need to write this.someField when referring to a member field, or this.someFunction() for a member method.

Fortunately the compiler will remind you when you forget it. This is why software developers like compilers: they tell you your mistakes before they happen at runtime!

Interface Fields are not Constants

Constants in TypeScript interfaces are not possible. Why would I like to have constants in interfaces? Because a method of that interface may return a constant that the caller needs to recognize, and I would like to keep such constants together with the method. Same for parameters.

Both Java and TypeScript allow to have fields in interfaces. But Java interface fields are constants, while TypeScript interface fields are variables by default, and can not be initialized in the interface.

interface Colors
{
    GREEN: string = "Green";
}

This will give you a compile error:

error TS1246: An interface property cannot have an initializer.

So then, let's see if we can have constant fields in a class:

interface Dimension
{
    width: number;
    height: number;
}

class DimensionImpl implements Dimension
{
    const width: number;  // compile error!
    const height: number;  // compile error!

    ....
}

Trying to translate this, the compiler will tell you

error TS1248: A class member cannot have the 'const' keyword.

Now you can do it the Java way:

interface Dimension
{
    getWidth(): number;
    getHeight(): number;
}

class DimensionImpl implements Dimension
{
    private width: number;
    private height: number;

    ....

    getWidth(): number {
        return this.width;
    }
    getHeight(): number {
        return this.height;
    }
}

Or you can investigate and do it how TypeScript does immutable fields:

interface Dimension
{
    readonly width: number;
    readonly height: number;
}

class DimensionImpl implements Dimension
{
    readonly width: number;
    readonly height: number;

    ....

}

Of course readonly is not intuitive when having the ES6 const keyword that is responsible for immutability.

No Real Function Overloading

Try to compile following TypeScript code:

interface Point
{
    x: number;
    y: number;
    distance(): number;
    distance(other: Point): number;
}

class PointImpl implements Point
{ 
    readonly x: number;
    readonly y: number;

    ....

    distance(): number {
        return this.distance(new PointImpl(0, 0));
    }
 
    distance(other: Point): number {
        const distanceX = this.distanceX(other);
        const distanceY = this.distanceY(other);
        return Math.sqrt(distanceX * distanceX + distanceY * distanceY);
    }

    ....  // distanceX() and distanceY() implementations
}

You will get following compile error from class PointImpl (not from interface Point):

error TS2393: Duplicate function implementation.

So is the promise of function overloading in TypeScript a hoax? Not completely. You need to provide everything in just one implementation, and forward to that via empty function signatures:

interface Point
{
    x: number;
    y: number;
    distance(): number;
    distance(other: Point): number;
}

class PointImpl implements Point
{ 
    readonly x: number;
    readonly y: number;

    ....

    distance(): number;  // you could also leave this out completely!
 
    distance(other?: Point): number {
        if ( ! other )
            other = new PointImpl(0, 0);
   
        const distanceX = this.distanceX(other);
        const distanceY = this.distanceY(other);
        return Math.sqrt(distanceX * distanceX + distanceY * distanceY);
    }

    ....  // distanceX() and distanceY() implementations
}

For sure this is a surprise for OO programmers. Mind the question mark after the parameter other. It makes the parameter nullable. This is the TypeScript way of function overloading.

TypeScript Example Implementation

So here are my TypeScript interfaces and classes for Point, Dimension and Rectangle. The interface Rectangle extends both Point and Dimension. The implementation RectangleImpl extends PointImpl and holds a Dimension delegate, because it can extend just one super-class (TypeScript single inheritance), but needs to implement Dimension. Thus it must somehow duplicate the Dimension interface.

I had all files in just one directory, and compiled them with:

tsc -t ES6 *.ts
Interfaces
Dimension.ts
export interface Dimension
{
    readonly width: number;
    readonly height: number;
    area(): number;
}
Point.ts
export interface Point
{
    readonly x: number;
    readonly y: number;
    distance(): number;
    distance(other: Point): number;
    transform(origin: Point): Point;
}
Rectangle.ts
import { Point } from "./Point.js";
import { Dimension } from "./Dimension.js";

export interface Rectangle extends Point, Dimension
{
    move(origin: Point): Rectangle;
    resize(newDimension: Dimension): Rectangle;
}
Classes
DimensionImpl.ts
import { Dimension } from "./Dimension.js";

export class DimensionImpl implements Dimension
{
    readonly width: number;
    readonly height: number;

    constructor(width: number, height: number)    {
        this.width = width;
        this.height = height;
    }
    
    area(): number    {
        return this.width * this.height;
    }
}
PointImpl.ts
import { Point } from "./Point.js";

export class PointImpl implements Point
{    
    readonly x: number;
    readonly y: number;

    constructor(x: number, y: number)    {
        this.x = x;
        this.y = y;
    }
    
    distance(other?: Point): number    {
        if ( ! other )
            other = new PointImpl(0, 0);
            
        const distanceX = this.distanceX(other);
        const distanceY = this.distanceY(other);
        return Math.sqrt(distanceX * distanceX + distanceY * distanceY);
    }
    
    transform(origin: Point): Point    {
        return new PointImpl(this.distanceX(origin), this.distanceY(origin));
    }

    private distanceX(other: Point): number    {
        return this.x - other.x;
    }
    private distanceY(other: Point): number    {
        return this.y - other.y;
    }
}
RectangleImpl.ts
import { Point } from "./Point.js";
import { PointImpl } from "./PointImpl.js";
import { Dimension } from "./Dimension.js";
import { Rectangle } from "./Rectangle.js";

export class RectangleImpl extends PointImpl implements Rectangle
{
    private readonly dimension: Dimension;

    constructor(origin: Point, dimension: Dimension)    {
        super(origin.x, origin.y);
        this.dimension = dimension;
    }
    
    // START Dimension delegates
    
    width: number = this.dimension.width;
    height: number = this.dimension.height;

    area(): number    {
        return this.dimension.area();
    }
    
    // END Dimension delegates
    
    resize(newDimension: Dimension): Rectangle    {
        return new RectangleImpl(this, newDimension);
    }
    move(newOrigin: Point): Rectangle    {
        return new RectangleImpl(newOrigin, this.dimension);
    }
}

Mind that the imports name .js files to be ES6-compatible. It would not work with .ts files. It would work with no extension at all, but this is not ES6-compatible. In other words, the TypeScript compiler, in ES6 mode, analyses the dependency tree and compiles bottom-up!

A Strange Compile Result

I just compiled these sources, this worked, but I did not test them yet. As much as I see now, the compilation goes horribly wrong sometimes. When using the compiled classes, I get a runtime (!) error

TypeError: this.dimension is undefined

from RectangleImpl.js line 6:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { PointImpl } from "./PointImpl.js";
export class RectangleImpl extends PointImpl {
    constructor(origin, dimension) {
        super(origin.x, origin.y);
        // START Dimension delegates
        this.width = this.dimension.width;
        this.height = this.dimension.height;
        this.dimension = dimension;
    }
    ....
}

The bug is obvious: this.width = this.dimension.width can not work when this.dimension = dimension is done two lines later!

This has been compiled by TypeScript from following source (snippet):

export class RectangleImpl extends PointImpl implements Rectangle
{
    private readonly dimension: Dimension;

    constructor(origin: Point, dimension: Dimension)    {
        super(origin.x, origin.y);
        this.dimension = dimension;
    }
    
    // START Dimension delegates
    
    width: number = this.dimension.width;
    height: number = this.dimension.height;
    ....
}

I hoped that I can forward x and y to dimension that way, but there seems to be no easy solution for forwarding properties to a delegate object. Will this be fixed by the TypeScript team?

Meanwhile I fixed this by storing the values (redundantly) in constructor:

export class RectangleImpl extends PointImpl implements Rectangle
{
    readonly width: number;
    readonly height: number;
    private readonly dimension: Dimension;

    constructor(origin: Point, dimension: Dimension)    {
        super(origin.x, origin.y);
        this.dimension = dimension;
        this.width = dimension.width;
        this.height = dimension.height;
    }
    ....
}

The problem is obvious: the value for width is now stored two times, once in the delegate dimension, once in RectangleImpl.

Readonly Must Be in Interface

Having the readonly keyword only on the class property is not enough to make the compiler check for write accesses. Following code will not give you a compile error due to assigning dimension.width a new value:

interface Dimension
{
    width: number;
    height: number;
}

class DimensionImpl implements Dimension
{
    readonly width: number;
    readonly height: number;

    constructor(width: number, height: number) {
        this.width = width;
        this.height = height;
    }
}

const dimension: Dimension = new DimensionImpl(1, 2);
dimension.width = 999;  // NOT a compile error!!!

You need to state readonly also in the interface:

interface Dimension
{
    readonly width: number;
    readonly height: number;
}

....

const dimension: Dimension = new DimensionImpl(1, 2);
dimension.width = 999;  // the needed compile error.

Now we get the necessary access check:

error TS2540: Cannot assign to 'width' because it is a constant or a read-only property.

Conclusion

Some techniques that look promising and are accepted by the compiler seem to cause troubles at runtime. That means unit tests are indispensable also with TypeScript, albeit of strong type checks.

Another big problem seems to be dependency management. I could not make my ES6 imports run with nodejs. It gave me SyntaxError: Unexpected token import. Installing the babel transpiler libraries did not help so far (working on it).

There are many more differences between Java and TypeScript concerning interfaces and classes, I just mentioned a few, and will continue to blog them. For example, TypeScript interfaces can determine constructors (see ClockConstructor).

Integrating a new language that provides so much freedom makes common life hard. Where are the programming languages that provide just what's needed, and thus support common sense actively?




Samstag, 7. April 2018

Writing Understandable Source Code

It's not a coincidence that it is called "code", which denotes unreadable text. What software developers write is mostly hard to understand. Consequence is that it is also hard to maintain. What is hard to maintain will be replaced, because time requires changes. Replacing means giving up concepts that worked well. Will the new version have better concepts, will it be understandable, how long will it last?

If you once followed a software product several years, you will know that maintenance effort outweighs writing new source code by far. Moreover new source code sets future trends. Thus writing understandable code is a question of to be or not to be.

Who Writes Code

Software is mostly written by people that consider themselves to be engineers or technicians. But in fact software development is something between journalism and engineering.

In times of libraries and code reuse a developer has to read lots of API documentations and source code before he/she can start to work and apply the acquired knowledge. The implementations afterwards will reflect that reading, so he/she is kind of a reporter that "brings things to application".

But was that applied API actually understandable? When not, you would have needed a really good programmer to get things done maintainable. Now, what means "good programmer"?

A Piece of Code

Following is about rainy weather, sitting at home, and handling the house's windows in case it is windy or calm. English Sunday business.

Written by person A:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    private void handleWindowsAtRain()  {
        if (isWindy()) {
            closeUpwindWindows();

            if (smellInside())
                openDownwindWindows();
            else if (smellOutside())
                closeDownwindWindows();
        }
        else if (smellInside()) {
            openAllWindows();
        }
        else if (smellOutside()) {
            closeAllWindows();
        }
    }

And by person B:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    private void manageInletsAtRain(Inlets inlets) {
        boolean am = airMoving();
        boolean si = smogInside();
        boolean so = smogOutside();

        if (am)
            disableLuv(inlets);

        if (am && si)
            enableLee(inlets);

        if (am && so)
            disableLee(inlets);

        if (!am && si)
            enableAll(inlets);
        
        if (!am && so)
            disableAll(inlets);
    }

Both sources do the same.

How long did you need to verify that?
Are you sure that you found out?

That's how developers spend their time.

Can we do better?

Dictionaries

For Business

If you don't have one, developers will use whatever comes to their mind currently. So make sure that it is

  • "Window"
  • and not "Inlet"

In reality I have seen business dictionaries very rarely. If you ask for it, you are directed to the source code mostly. So code explains itself from code?

For Technics

This would be to make sure that it is

  • "open" and "close"
  • and not "enable" and "disable"

To avoid misunderstandings: this is not that nouns are business and verbs are technical. Both could be on each side.

I have never seen a technical dictionary in reality. Developers are expected to all use the same terms, and to speak the same language, by means of their telepathy skills. Everybody knows the difference between "hidden" and "invisible" ... don't you?

By the way:

  • if there is a business term that can replace the technical one, then use the business term!

Coding Directives

Yes, agreed, the first source snippet is the better one. Because its structure is logically clearer, and the wording is better. But how can you teach good coding style, and how check it? With reviews that last as long as writing the code lasted? Point the developers to thick books for which they will need a month to read, and a year to understand?

Question is if the second snippet isn't the better one, because it uses parameters instead of relying on class member fields. This makes code much more flexible for refactorings: Declare what you need to operate as parameter. Was this advice in the thick book you've been reading?

How can you convince developers that ...

  1. abbreviations of any kind, especially one-letter variable names
  2. unpronounceable names, unsearchable names
  3. technical prefixes, infixes and postfixes
  4. more than one term per concept ("fetch", "retrieve", "get", ...)
  5. unspecific general terms (like "process" or "manage")
  6. naming conventions that mediate application logic (also called "string programming")

.... are bad?

Common Sense

Finally it boils down to having good common sense. Agile programming demands it. People that are able to compromise, willing to spend time on discussions for finding good terms, and improve the old code that spells badly.

Code is not written by developers only, also business staff writes it. But whoever writes code does one thing:

  • connect technical and business logic

And that literally needs common sense.

Resume

A book that I really appreciate is Robert C. Martin's "Clean Code". It may be lengthy sometimes, and things may be missing, and it's a pity that it's not open source, but if you come over it, try to read from it as much as you can.

I can't give a definition of what makes a "good programmer". Maybe we shouldn't use the terms "good" and "bad" any more. What about "useful" and "confusing"?

  • The useful people are those that document their source code, that can explain and present their concepts, in a way that everybody knows the context and can follow. Those that make sure that everybody is actually following. And they know that writing understandable code requires care and time.

  • The confusing people are those that consider source code to be just the technical representation of "their" business, an unsolvable problem that will always leak, and thus it is not important to write understandable code, too expensive. All essential software is already written, we just need to build, deploy and sell it.

Don't write code for machines, write code for humans. Keep this in mind: "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."