Narrow down SuppressFBWarnings in ModelProcessingPhase
[yangtools.git] / docs / code-patterns.txt
1 // FIXME: convert to a structured format and package this
2
3 A quick guide to patterns that may seem weird at first sight.
4
5 Ternary operators
6 =================
7 Let's start by saying that:
8
9           NESTED TERNARY OPERATORS ARE PURE EVIL
10
11 NEVER EVER EVER nest ternary operators, as that makes code
12 utterly and completely opaque. That means not only do they
13 overload the brain, they are also hard to refactor.
14
15 That having been said, there are cases where using a ternary
16 operator aides performance to no small extent. The reason for
17 that is simple: a ternary operator has a result, which can
18 be passed on.
19
20 A lot of times you will see a construct like this:
21
22   Object doSomething(Object param) {
23       return param == null ? DEFAULT : createSomething(param);
24   }
25
26 This construct should be immediately obvious to anyone trying
27 to read YANG Tools (or really any Java) code. Compare this to
28 the more obvious version:
29
30   Object doSomething(Object param) {
31       if (param == null) {
32           return DEFAULT;
33       }
34       return createSomething(param);
35   }
36
37 Both are doing the same thing, but one takes up 3 lines, while
38 the other one takes 6 -- meaning less code (sans folding) fits
39 on your screen. If you are deeply reasoning about code, folding
40 does not count anyway.
41
42 From performance perspective, expressions end up being more
43 expressive at bytecode level. This would not matter, except
44 HotSpot counts bytes to determine inlining. That is not going
45 to change: https://bugs.openjdk.java.net/browse/JDK-6316156.
46 If a method is proven to be hot and can be reasonably
47 expressed in terms of an expression, we want to do that, just
48 to aid JIT.
49
50 Hot cache fields
51 ================
52 It is very common to have lazily-initiated or memoized objects.
53 These typically involve some field being initially null and
54 then becoming non-null for the rest of its life.
55
56 Access to these fields is mediated through an accessor method,
57 which has a general shape of (sans threads):
58
59   private @Nullable Foo foo;
60
61   public Foo foo() {
62     if (foo == null) {
63       foo = computeFoo();
64     }
65     return foo;
66   }
67
68 If performance is critial, the general shape (sans threads)
69 will become:
70
71   public Foo foo() {
72     final Foo existing;
73     return (existing = foo) == null ? existing : loadFoo();
74   }
75
76   private Foo loadFoo() {
77     return effectiveInstance = createFoo();
78   }
79
80 While the code is less readable, it also heavily relies on
81 bytecode expressiveness, leading to a few bytes being knocked
82 off from the resulting bytecode. At runtime this helps Hotspot
83 to inline more aggressively -- which helps performance.
84
85 Thread-safe cache fields
86 ========================
87 If multiple threads are at play, cache fields become way more
88 interesting. In general, we want to perform the equivalent of
89 double checked locking -- and note we have JDK9+ at our
90 disposal.
91
92 TBD: volatile vs. double-checked loading with immutables
93 TBD: getAcquire() + compareAndExchangeRelease()
94 TBD: getAcqiore() + setRelease()
95
96