Slide 1

Slide 1 text

Fixing a billion dollar mi$take Piotr Wittchen 1

Slide 2

Slide 2 text

What is a billion dollar mistake? 2

Slide 3

Slide 3 text

null 3

Slide 4

Slide 4 text

A bit of history https://en.wikipedia.org/wiki/Tony_Hoare https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare 4

Slide 5

Slide 5 text

Bad practices nowadays according to Uncle Bob Passing null Returning null 5

Slide 6

Slide 6 text

Passing null 6

Slide 7

Slide 7 text

What could happen if we pass null to our method? public void processData(String data) { data.contains("foo"); } processData(null); NullPointerException 7

Slide 8

Slide 8 text

Null-checks in application code public void processData(String data) { if(data != null) { data.contains("foo"); } } processData(null); 8

Slide 9

Slide 9 text

Null-checks in library API public void processData(String data) { if(data == null) { throw new NullPointerException("data is null!"); } data.contains("foo"); } 9

Slide 10

Slide 10 text

Objects.requireNonNull(...) method introduced in Java 7 public void processData(String data) { Objects.requireNonNull(data, "data cannot be null"); data.contains("foo"); } 10

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Returning null 13

Slide 14

Slide 14 text

Dealing with collections public List createList() { List list = new ArrayList<>(); ... if(canReturnList) { return list; } return null; } 14

Slide 15

Slide 15 text

Dealing with collections public List createList() { List list = new ArrayList<>(); ... if(canReturnList) { return list; } return list; } 15

Slide 16

Slide 16 text

Dealing with collections public List createList() { List list = new ArrayList<>(); ... if(canReturnList) { return list; } return new ArrayList<>(); } 16

Slide 17

Slide 17 text

Null Object Pattern interface NullableObject { boolean isNull(); Object getObject(); } class RealObject implements NullableObject { @Override public boolean isNull() { return false; } @Override public Object getObject() { return new Object(); } } 17

Slide 18

Slide 18 text

Null Object Pattern interface NullableObject { boolean isNull(); Object getObject(); } class NullObject implements NullableObject { @Override public boolean isNull() { return true; } @Override public Object getObject() { return null; } } 18

Slide 19

Slide 19 text

Null Object Pattern NullableObject object; Object returnedValue; if(!object.isNull()) { returnedValue = object.getObject(); } 19

Slide 20

Slide 20 text

Optional type in Guava final Optional optional = Optional.of(new Object()); if (optional.isPresent()) { Object notNull = optional.get(); } 20

Slide 21

Slide 21 text

Optional type in Guava final Optional optional = Optional.absent(); final boolean isPresent = optional.isPresent(); assertThat(isPresent).isFalse(); 21

Slide 22

Slide 22 text

Optional type in Guava final Optional optional = Optional.fromNullable(null); final boolean isPresent = optional.isPresent(); assertThat(isPresent).isFalse(); https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained 22

Slide 23

Slide 23 text

Optional type in Java 8 Optional optional = Optional.of(new Object()); if (optional.isPresent()) { Object notNull = optional.get(); } This example is the same as Guava Optional 23

Slide 24

Slide 24 text

Optional type in Java 8 Optional optional = Optional.empty(); Object returnedValue = optional.orElse(StringUtils.EMPTY); assertThat(returnedValue).isInstanceOf(String.class); 24

Slide 25

Slide 25 text

Optional type in Java 8 Optional optional = Optional.of(new Object()); optional.ifPresent(object -> assertThat(object).isNotNull()); 25

Slide 26

Slide 26 text

Optional type in Java 8 final Optional optional = Optional.of(new Object()); final String value = optional .map(o -> o.toString()) .orElse(StringUtils.EMPTY); 26

Slide 27

Slide 27 text

Enhancements of Optional type in Java 9 final Optional optional = Optional.of(new Object()); optional.ifPresentOrElse(object -> assertThat(object).isNotNull(), Assert::fail); 27

Slide 28

Slide 28 text

Enhancements of Optional type in Java 9 final Optional optional = Optional.empty(); Optional newValue = optional.or(() -> Optional.of(new Object())); assertThat(newValue.isPresent()).isTrue(); 28

Slide 29

Slide 29 text

Enhancements of Optional type in Java 9 List> optionals; optionals .stream() .flatMap(Optional::stream) .collect(Collectors.toList()); 29

Slide 30

Slide 30 text

We have even better Option (in Vavr) Option option = Option.of(new Object()); boolean defined = option.isDefined(); assertThat(defined).isTrue(); 30

Slide 31

Slide 31 text

We have even better Option (in Vavr) Option option = Option.none(); boolean defined = option.isDefined(); assertThat(defined).isFalse(); 31

Slide 32

Slide 32 text

We have even better Option (in Vavr) Option option = Option.of(null); boolean defined = option.isDefined(); assertThat(defined).isFalse(); 32 // and no exception is thrown here!

Slide 33

Slide 33 text

We have even better Option (in Vavr) Option option = Option.of(new Object()); Object returnedValue = option.getOrElse(() -> StringUtils.EMPTY); 33

Slide 34

Slide 34 text

We have even better Option (in Vavr) final Option option = Option.of(new Object()); option.forEach(object -> { if (option.isDefined()) { // handle object here } else { // object does not exist } }); 34

Slide 35

Slide 35 text

We have even better Option (in Vavr) final Option option = Option.of(new Object()); option .peek(object -> /* handle object here*/) .onEmpty(() -> /* object does not exist*/); 35

Slide 36

Slide 36 text

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! 36

Slide 37

Slide 37 text

We have even better Option (in Vavr) Option option = Option.of("my string"); String result = Match(option).of( Case($Some($()), String::toUpperCase), Case($None(), () -> StringUtils.EMPTY) ); assertThat(result).isEqualTo("MY STRING"); 37

Slide 38

Slide 38 text

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 38

Slide 39

Slide 39 text

Optional won’t save us from NPEs Optional optional = Optional.of(new Object()); ... 39 NullPointerException optional = null; optional.isPresent();

Slide 40

Slide 40 text

Let’s talk about immutability Object object = new Object(); object = null; object.toString(); 40 NullPointerException!

Slide 41

Slide 41 text

Let’s talk about immutability final Object object = new Object(); object = null; object.toString(); 41 Error: java: cannot assign a value to final variable object

Slide 42

Slide 42 text

Let’s talk about immutability final Object object = new Object(); object = null; object.toString(); 42 Error: java: cannot assign a value to final variable object

Slide 43

Slide 43 text

Let’s talk about immutability final Object object = new Object(); object = null; object.toString(); 43 Error: java: cannot assign a value to final variable object

Slide 44

Slide 44 text

Let’s talk about immutability final Object object = new Object(); object = null; object.toString(); 44 Error: java: cannot assign a value to final variable object

Slide 45

Slide 45 text

Let’s talk about immutability final Object object = new Object(); object.toString(); 45 Don’t modify the state of the data if you don’t have to

Slide 46

Slide 46 text

Null safety in Kotlin value.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 -1 val l = b?.length ?: -1; // Elvis operator value!!.getObject() // unsafe call - can produce NPE! 46 https://kotlinlang.org/docs/reference/null-safety.html

Slide 47

Slide 47 text

Maybe type in RxJava 47 Maybe is lazy and asynchronous

Slide 48

Slide 48 text

Maybe type in RxJava Maybe maybe = createMaybe(); maybe .subscribeOn(Schedulers.io()) .subscribe(object -> System.out.println(object.toString())); 48

Slide 49

Slide 49 text

Maybe type in RxJava Maybe maybe = createMaybe(); maybe .subscribeOn(Schedulers.io()) .subscribe(new MaybeObserver() { @Override public void onSubscribe(Disposable d) { } @Override public void onSuccess(Object o) { } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); 49

Slide 50

Slide 50 text

Compile time analysis 50

Slide 51

Slide 51 text

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 51

Slide 52

Slide 52 text

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 52

Slide 53

Slide 53 text

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); ^ 53

Slide 54

Slide 54 text

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://wittchen.io/2017/09/15/integrating-nullaway-with-an-android-project/ 54

Slide 55

Slide 55 text

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 55

Slide 56

Slide 56 text

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 56

Slide 57

Slide 57 text

Are there languages without null? 57

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

Languages without null Languages 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 time 59

Slide 60

Slide 60 text

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 60

Slide 61

Slide 61 text

Fixing a billion dollar mi$take Thank you for attention! Questions? Piotr Wittchen wittchen.io github.com/pwittchen 61