DEVOXX UK 2019, London: Talk by Andreas Zitzelsberger (@andreasz82, Principal Software Architect at QAware)
=== Please download slides if blurred! ===
Watch the full talk on YouTube: https://www.youtube.com/watch?v=Gcwlt6_uhQU
Abstract:
There’s good code, and there’s bad code. There also is code so spectacularly bad that it leaves a lasting impression. This talk will show some of the most egregious code from several years of developing software so that we may learn from the mistakes of the past and be entertained.
All code is real (but anonymized) and ran in production.
9. if (clazz != null) {
header.concat(LayoutConst.CLASS_NAME_STR);
header.concat(clazz.getName());
header.concat(LayoutConst.NEW_LINE);
}
Early implementation of
github.com/kelseyhightower/noco
de
10. public final static String NAME = new String("PIE DIAGRAM");
String surplus = new String(" ");
new String(Long.toString(rightPoint));
new String("col" + String.valueOf(z + 2));
Me want objects!
GC
14. } catch (Exception e) {
// improbable exceptions, throw a runtime exception
// to avoid the declaration in the method-signature
throw new RuntimeException( "... failed", e);
}
15. } catch (Exception ex) {
// this exception will be ignored
// because it cannot be sensibly handled
;
} Why is there a
semicolon?
16. } catch (SQLException sqlException) {
; // to be compliant with rule NoEmptyCatchBlocks
}
Ah, that’s why!
21. HttpServletResponseWrapper {
/* ... */
public void setHeader(String arg0, String arg1) {
// in this case do nothing here,
// because we are setting it in the filter
}
public void setContentType(String arg0) {
// in this case do nothing here,
// because we are setting it in the filter
}
Breaks contract of
HttpServletResponse
22. public class PasswordEncryptor {
private static final byte[] ALGO = new byte[]{68, 69, 83};
public static String encrypt(String str) throws
BadPaddingException, IllegalBlockSizeException,
NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, UnsupportedEncodingException {
// ...
Cipher cipher = Cipher.getInstance(new String(ALGO));
cipher.init(1, new SecretKeySpec(key,
new String(ALGO)));
// ...
}
}
D E S
24. public class ServiceInvocationHandler implements InvocationHandler {
private final BusinessService underlyingBusinessService;
private final BusinessService derivedFromBusinessService;
public Object invoke(/* ... */ ) throws Throwable {
/* ... */
}
public static Object getService(/* ... */) {
/* ... */
}
}
Let’s call these
delegate and
caller for the sake
of clarity…
25. public Object invoke(final Object proxy, final Method method,
final Object[] args) throws Throwable {
try {
if (caller == null)
delegate.setSession(HibernateUtil.getSessionFactory()
.getCurrentSession());
else {
Assert.isNotNull(caller.getSession());
delegate.setSession(caller.getSession());
}
delegate.beginTransaction();
final Object ret = method.invoke(delegate, args);
// continued ...
No Caller → New
Hibernate session
Otherwise, use
the caller’s
session
Wait, what if there
already is an open
transaction?
26. if (caller == null)
delegate.commit();
if (delegate instanceof ServiceWithAssociatedThread
&& ((ServiceWithAssociatedThread) delegate)
.hasAssociatedThread()) {
((ServiceWithAssociatedThread) delegate)
.startAssociateThread();
((ServiceWithAssociatedThread) delegate)
.removeAssociateThread();
}
return ret;
} catch (final Throwable throwable) {
// continued …
}
Unfinished
transaction if
there is a caller
What could go
wrong?
27. } catch (final Throwable throwable) {
Logger.error(ServiceInvocationHandler.class,
„Error ...", throwable);
if (caller == null && delegate.hasTransaction())
delegate.rollback();
else if (caller != null && caller.hasTransaction())
caller.rollback();
throw throwable.getCause();
} finally {
if (delegate.hasSession()) {
//if (caller != null)
// delegate.close();
delegate.setSession(null);
}
Wait, what?
Wait for the GC
to clean up after
us
Modify stack trace,
possible
NullPointerException
30. protected void reset() {
String[] classesForReset =
{
„com.acmecorp...legitimaton...XService",
„com.acmecorp...legitimaton...YService",
"com.acmecorp...legitimaton...ZService",
// ...
};
// continued ...
Boss music
starts…
31. for (int i = 0; i < classesForReset.length; i++) {
try {
Class class = class.forName(classesForReset[i]);
Method method = class.getDeclaredMethod(
„reset", new Class[0]);
method.invoke(null, null);
} catch Exception e) {
System.err.println(/* ... */);
e.printStackTrace(System.err);
}
}
Call a static reset
method on each class
for each request
32. How bad can it be?
public static void reset() {
ldapFilters = new HashMap();
}
Filters for per-
user LDAP
queries
public static void reset() {
sslSocketFactory = null;
}
New connections
for each request
33.
34. What (probably) has happened
• Stored session state in static variables (maybe a former C programmer?)
• We need a reset() method, but it has to be static
• Can’t use an interface for static methods
• Call them by reflection
• Forget about this code and have it run in production...
• ...for over 10 years
• ...in almost 300 applications