[quality meetup] piotr wittchen - fixing a billion dollar mistake

63
1

Upload: future-processing

Post on 16-Mar-2018

98 views

Category:

Software


2 download

TRANSCRIPT

1

2

Fixing a billion dollar mi$take

Piotr Wittchen

3

What is a billion dollar mistake?

4

null

5

A bit of history

https://en.wikipedia.org/wiki/Tony_Hoare

https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare 6

Bad practices nowadays according to Uncle Bob

Passing nullReturning null

7

Passing null

8

What could happen if we pass null to our method?

public void processData(String data) { data.contains("foo");}

processData(null);

NullPointerException

9

Null-checks in application code

public void processData(String data) { if(data != null) { data.contains("foo"); }}

processData(null);

10

Null-checks in library API

public void processData(String data) { if(data == null) { throw new NullPointerException("data is null!"); }

data.contains("foo");}

11

Objects.requireNonNull(...) method introduced in Java 7

public void processData(String data) { Objects.requireNonNull(data, "data cannot be null"); data.contains("foo");}

12

Guava and Preconditions

public void processData(String data) { Preconditions.checkNotNull(data ,"data cannot be null"); data.contains("foo");}

13

@Nonnull Annotation

public void processData(@Nonnull String data) { data.contains("foo");}

14

Returning null

15

Dealing with collections

public List<Integer> createList() { List<Integer> list = new ArrayList<>();

...

if(canReturnList) { return list; }

return null;} 16

Dealing with collections

public List<Integer> createList() { List<Integer> list = new ArrayList<>();

...

if(canReturnList) { return list; }

return list;} 17

Dealing with collections

public List<Integer> createList() { List<Integer> list = new ArrayList<>();

...

if(canReturnList) { return list; }

return new ArrayList<>();} 18

Null Object Patterninterface NullableObject { boolean isNull(); Object getObject();}

class RealObject implements NullableObject { @Override public boolean isNull() { return false; }

@Override public Object getObject() { return new Object(); }}

19

Null Object Patterninterface NullableObject { boolean isNull(); Object getObject();}

class NullObject implements NullableObject { @Override public boolean isNull() { return true; }

@Override public Object getObject() { return null; }}

20

Null Object Pattern

NullableObject object;Object returnedValue;

if(!object.isNull()) { returnedValue = object.getObject();}

21

Optional type in Guavafinal Optional<Object> optional = Optional.of(new Object());

if (optional.isPresent()) { Object notNull = optional.get();}

22

Optional type in Guavafinal Optional<Object> optional = Optional.absent();

final boolean isPresent = optional.isPresent();

assertThat(isPresent).isFalse();

23

Optional type in Guavafinal Optional<Object> optional = Optional.fromNullable(null);

final boolean isPresent = optional.isPresent();

assertThat(isPresent).isFalse();

https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained

24

Optional type in Java 8

Optional<Object> optional = Optional.of(new Object());

if (optional.isPresent()) { Object notNull = optional.get();}

This example is the same as Guava Optional

25

Optional type in Java 8Optional<Object> optional = Optional.empty();

Object returnedValue = optional.orElse(StringUtils.EMPTY);

assertThat(returnedValue).isInstanceOf(String.class);

26

Optional type in Java 8Optional<Object> optional = Optional.of(new Object());

optional.ifPresent(object -> assertThat(object).isNotNull());

27

Optional type in Java 8final Optional<Object> optional = Optional.of(new Object());

final String value = optional .map(o -> o.toString()) .orElse(StringUtils.EMPTY);

28

Enhancements of Optional type in Java 9final Optional<Object> optional = Optional.of(new Object());

optional.ifPresentOrElse(object -> assertThat(object).isNotNull(), Assert::fail);

29

Enhancements of Optional type in Java 9final Optional<Object> optional = Optional.empty();

Optional<Object> newValue = optional.or(() -> Optional.of(new Object()));

assertThat(newValue.isPresent()).isTrue();

30

Enhancements of Optional type in Java 9

List<Optional<Object>> optionals;

optionals .stream() .flatMap(Optional::stream) .collect(Collectors.toList());

31

We have even better Option (in Vavr)Option<Object> option = Option.of(new Object());

boolean defined = option.isDefined();

assertThat(defined).isTrue();

32

We have even better Option (in Vavr)Option<Object> option = Option.none();

boolean defined = option.isDefined();

assertThat(defined).isFalse();

33

We have even better Option (in Vavr)Option<Object> option = Option.of(null);

boolean defined = option.isDefined();

assertThat(defined).isFalse();

34

// and no exception is thrown here!

We have even better Option (in Vavr)Option<Object> option = Option.of(new Object());

Object returnedValue = option.getOrElse(() -> StringUtils.EMPTY);

35

We have even better Option (in Vavr)final Option<Object> option = Option.of(new Object());

option.forEach(object -> { if (option.isDefined()) { // handle object here } else { // object does not exist }});

36

We have even better Option (in Vavr)final Option<Object> option = Option.of(new Object());

option .peek(object -> /* handle object here*/) .onEmpty(() -> /* object does not exist*/);

37

We have even better Option (in Vavr)private Object getObject() { throw new NullPointerException("Surprise! There's no Object!");}

final Object object = Try .of(this::getObject) .toOption() .getOrElse(new Object());

assertThat(object).isNotNull();

// and no exception is thrown here!

38

We have even better Option (in Vavr)Option<String> option = Option.of("my string");

String result = Match(option).of( Case($Some($()), String::toUpperCase), Case($None(), () -> StringUtils.EMPTY));

assertThat(result).isEqualTo("MY STRING");

39

Option type and Vavr

References:

● http://www.vavr.io● http://www.vavr.io/vavr-docs/#_option ● https://softwaremill.com/do-we-have-better-option-here● https://dev.to/koenighotze/in-praise-of-vavrs-option

40

Optional won’t save us from NPEsOptional<Object> optional = Optional.of(new Object());...

41

NullPointerException

optional = null;

optional.isPresent();

Let’s talk about immutabilityObject object = new Object();

object = null;

object.toString();

42

NullPointerException!

Let’s talk about immutabilityfinal Object object = new Object();

object = null;

object.toString();

43

Error: java: cannot assign a value to final variable object

Let’s talk about immutabilityfinal Object object = new Object();

object = null;

object.toString();

44

Error: java: cannot assign a value to final variable object

Let’s talk about immutabilityfinal Object object = new Object();

object = null;

object.toString();

45

Error: java: cannot assign a value to final variable object

Let’s talk about immutabilityfinal Object object = new Object();

object = null;

object.toString();

46

Error: java: cannot assign a value to final variable object

Let’s talk about immutabilityfinal Object object = new Object();

object.toString();

47

Don’t modify the state of the data if you don’t have to

Null safety in Kotlinvalue.getObject() // IntelliJ will highlight this as an error if there could be NPE!

if (value != null) { // null-check value.getObject()}

value?.getObject() // safe call

val l: Int = if (b != null) b.length else -1val l = b?.length ?: -1; // Elvis operator

value!!.getObject() // unsafe call - can produce NPE!

48

https://kotlinlang.org/docs/reference/null-safety.html

Maybe type in RxJava

49

Maybe is lazy and asynchronous

Maybe type in RxJavaMaybe<Object> maybe = createMaybe();

maybe .subscribeOn(Schedulers.io()) .subscribe(object -> System.out.println(object.toString()));

50

Maybe type in RxJavaMaybe<Object> maybe = createMaybe();

maybe .subscribeOn(Schedulers.io()) .subscribe(new MaybeObserver<Object>() { @Override public void onSubscribe(Disposable d) { }

@Override public void onSuccess(Object o) { }

@Override public void onError(Throwable e) { }

@Override public void onComplete() { } });

51

Compile time analysis

52

Error Prone

Error Prone is a static analysis tool for Java developed at Google that catches common programming mistakes at compile-time.

https://github.com/google/error-prone

53

Null Away

NullAway is a tool developed at Uber built as an Error Prone plugin to help eliminate NullPointerExceptions (NPEs) in your Java code.

https://github.com/uber/NullAway

54

Null Away

static void log(Object x) { System.out.println(x.toString());}static void foo() { log(null);}

warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required

log(null);

^

55

Null Away

Integration with Gradle-based Java project

https://github.com/uber/NullAway#java-non-android

Integration with Gradle-based Android project

https://github.com/uber/NullAway#android http://blog.wittchen.biz.pl/integrating-errorprone-and-nullaway-with-an-android-project/

56

Keeping up good practices in greenfield projects

● Choose one approach or several approaches● Apply chosen solutions to your work routine and CI server● Perform code reviews carefully● Be consistent

57

How about legacy code?

● Apply proper rules to the new code (see previous slide)● Perform null-checks and write more unit tests for the old code● Keep backward compatibility when necessary● Gradually deprecate old code and introduce new rules

58

Are there languages without null?

59

Are there languages without null/nil/None/etc.?

60

Languages without nullLanguages with Option type:● Rust● Ocaml● Standard ML● F#● Scala

Languages with Maybe type:● Elm● Haskell

and others I could miss...

Crystal has nil, but compiler prevents NPEs at compile time61

Summary

● Do not pass null● Do not return null● Return empty collections instead of null● Use Optional/Option type for returning “nullable” sync data● Use RxJava Maybe type for returning “nullable” async data● Make data in your code as much immutable as possible● Use compile time analysis and static code analysis● Use language without null or with null-safety features when you can● Be careful during code reviews● Be consistent during applying good practices

62

Fixing a billion dollar mi$takeThank you for attention! Questions?

Piotr Wittchenwittchen.biz.pl

github.com/pwittchentwitter.com/piotr_wittchen

63