Dienstag, 24. März 2015

New Junior Colleague - a Chance to Learn

Recently I got a new colleague. A young guy, now working as a developer in my project. In my first review of one of his changes I saw the flaws again we just managed to widely eliminate in our team.

In this case it was about mutability. Seeking immutability wherever possible is one of my favorite best practices. I cannot live with unnecessary setters in our code. So, I could not help but play the dog in the manger. His argumentation was that he likes to always have a default constructor to allow for "easy mocking" of every object. And, when you force to caller to provide every parameter during construction of a tree of related objects, this accumulates to a bigger problem. I think in the end I could made him aware of the advantages of unchangeable elements in the code, but I don't want to dive into this specific topic here.

My realization was that the young crowd that comes from college is still in the same necessity to get the practical finishing it ever needed. I think this has not changed in the last decade.

Besides my view as a senior to the early stage of knowledge of these junior developers, I am at the same time aware of the fact that there is also potential to learn new, fresh ideas from them.

Sometimes a beloved best practice got a bit long in the tooth. I am actually thankful for that, nothing could be worse than ever working in the ivory tower and, slowly but surely, getting obsolete!

Furthermore you learn that it will always be necessary to build software with people in every stage of development. The process and the software architecture should compensate that. If it breaks, not the poor junior is to blame, but the framework!

Dienstag, 17. Februar 2015

How to generate a database schema report with Maven and Schemaspy

Lately I wanted to setup a continuously generated schema diagram on the database layout for a project. I finally managed to achieve this with SchemaSpy and Maven.
Below you find the relevant parts from my pom. I bound the report generation to the "site" phase. The tricky thing is that SchemaSpy requires the database driver library as a parameter. I extracted it from the build classpath into a property, see below.

    
<project xmlns="http://maven.apache.org/POM/4.0.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
  http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>eckstein</groupId>
  <artifactId>test</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <reporting>
    <plugins>
      <plugin>
        <groupId>com.wakaleo.schemaspy</groupId>
        <artifactId>maven-schemaspy-plugin</artifactId>
        <configuration>
          <databaseType>mysql</databaseType>
          <database>${db.name}</database>
          <host>${db.host}</host>
          <user>${db.username}</user>
          <password>${db.password}</password>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-site-plugin</artifactId>
        <version>3.4</version>
        <configuration>
          <!-- disable all the default Maven reports -->
          <generateReports>false</generateReports>
        </configuration>
      </plugin>
    </plugins>
  </reporting>

  <pluginRepositories>
    <pluginRepository>
      <id>Wakaleo Repository</id>
      <url>http://www.wakaleo.com/maven/repos/</url>
    </pluginRepository>
  </pluginRepositories>
  
</project>

With the configuration above the reports get generated if you run this Maven command in the project:

mvn site -Ddb.name=<database-name> -Ddb.host=<mydatabase-host> \
         -Ddb.username=<user> -Ddb.password=<password>

The reports end up under target/site/schemaspy. Running it on your continuous build server enables you to have always an up-to-date report available. You can then link to it from your corporate Wiki or Blog.
 
To have the graphical diagrams generated Schemaspy requires Graphviz installed on the systems it runs on. If that's the case for a Linux installation you can check by testing for the dot command:
dot -?
If it's not there you should install it, e.g. for Ubuntu this way:
sudo apt-get install graphviz
The generated report looks like below. Images are generated as DOT files, but also exported to PNG which can then nicely get embedded into your online documentation!


Dienstag, 27. Januar 2015

Be careful with the parametrized log methods!

Most logging frameworks provide handy methods to pass in a formatted message together with arbitrary parameters. But as simple the call looks, you have to know that there are consequences!

logger.info("Successfully processed {}.", heavyObject); 

Most of us would automatically assume that the execution of the line above leads to a call to heavyObject.toString() inside logger.info(). But it does not!

Depending on the logging framework, but most likely, this will create an instance of an object representing the logging event. The event object holds references to the passed message arguments, here "heavyObject". If you think about the logging concepts this is quite clear. The logger forwards the events to the "appenders". The idea of the appender interface includes that there can be various types with manifold functions. To give the appenders maximum flexibility they have to get the events with all the available information. This includes the message argument object.

So, the concept of logging events holding references to the arbitrary input objects is OK and brings a lot of possibilities. However, the effect is that there is another place holding references to your objects! This means:
  • It can be a garbage collection issue for your application!
  • Content consistency requires immutability!

Issue 1, Garbage Collection 

I saw the garbage collection problem in a project lately. The application crashed with OutOfMemoryException at 6 GB. The reason was an asynchronous log appender sending logging events over the network. Inside it was holding a queue buffering events during network latencies. Everything worked fine as long as there were no real connections problems. But, as you can imagine, some day the network problem happened. The appender was getting high loads, the queue grew and collected thousands of entries. And some of them were really big!

JVM heap usage during network problems to remote log receiver

I know, the developers that wrote the logging statements didn't want more than just a toString() of the arguments. However, passed were objects holding the complete tree of an unmarshalled, mega bytes big XML document-- and this every couple of seconds!

Issue 2, Content Consistency

When you pass an object to the logger, you don't know when the data will actually be accessed, i.e. when the log statement is finally written. If your objects state is mutable and the reference is further processed in your applications, it is very likely that your log output is falsified! This is a real issue! It annuls the basic idea of the logging to help you to understand the state of your application.

When I discussed this with somebody that is involved in development of logging frameworks he told me that passing a mutable objects to a logger is not a good practice. I heard that advice the first time. So, please take you this to heart!

Conclusion

The bottom line is that there are advantages in the logging via message template with parameters. The major one is performance. The application thread is kept fast by passing the effort for the message formatting, including the toString(), to the (potentially) asynchronous log writer.

However, every developer should be aware that this is another handover of an object reference to something out of scope. If you prefer or depend on the object to be transient, you better do the toString() explicitly!

logger.info("Successfully processed {}.", heavyObject.toString()); 

Sonntag, 25. Januar 2015

Warum sind best pratices in der Software-Entwicklung so uncool?

Eckstein:

Es gibt eine Menge Ressourcen im Netz über best practises in der Programmierung, Design Patterns, sowie Erfahrungsberichte. Eigentlich sollten wir, als logisch handelnde Informatiker, doch durchweg auf höchstem Niveau programmieren. Meiner Meinung nach, ist das jedoch absolut nicht der Fall. Es scheitert an der individuellen Eitelkeit des Software-Nerds.

Ist es nicht das Schöne am Programmieren, dass man versucht das Handwerk zur Kunst zu machen? Dass man seinen Beruf vom stumpfen Umsetzer abgrenzt und Ansporn in täglichem Denksport findet? Dazu gehört, dass man sich ständig weiter entwickelt und ständig die eigene Reife in Frage stellt.

In der Realität trifft man jedoch viel zu häufig auf Entwickler, die diese Euphorie nicht teilen, die ihre Aufgabe im zügigen Abliefern verstehen und kreatives Software-Design eher als übertriebenen Perfektionismus sehen.

    "Over-Engeneering!"
    "Wir designen uns zu Tode!"

Der code ist unser Werkstück. Jeder würde dem Schreiner glauben, dass er respektvoll mit seinem Rohstoff Holz umgehen will. Dass er am Ende etwas Geschmackvolles abliefern will. Bei Software-Entwicklern gilt das oft als pedantisch. Eine schnelle Lösung, die nicht mehr tut als zu funktionieren, macht den Manager und Kunden glücklich- für den Moment.

    "Nicht schön, aber funktioniert!"
    "Schnell, simpel, läuft!"

Den Mehrwert einer Lösung von höherer Qualität erkennen die wenigsten Programmier-Laien, ein hochwertiges Schreinerstück hingegen ist landläufig einfacher zu verkaufen.

Hansen:

Eckstein, ich glaube du siehst das vielleicht ein wenig verbissen. Die meisten Entwickler wissen wann Code nicht optimal ist. Sie setzen den Fokus nur nicht gemäß deiner Ideale. Viele Anwendungen oder Bibliotheken haben eine absehbare Lebenszeit- vier, fünf Jahre vielleicht. Lohnt sich da immer der, sorry, Perfektionismus?

Eckstein: 

Ja, ich gebe zu da hast du nicht ganz unrecht. Code wird sowieso nie perfekt sein. Jedoch glaube ich, dass sich aus sorgsam entworfenem Code viel mehr weiterer Nutzen ziehen lässt. Und, dass schlechter Code schwer wartbar und erweiterbar ist, ist doch allgemein bekannt. Ich glaube wirklich, dass viele Entwickler sich gar nicht bewusst sind, dass sie schlechten Code schreiben. Und der Grund ist, dass sie desinteressiert sind am Stand der Diskussion um beste Verfahrensweisen.

Hansen:

Ja, schon mal gesehen. Kann es aber sein, dass das auch zum großen Teil die Nachwuchs-Entwickler sind? Die musst du heraus rechnen! Ich denke am Anfang war deine "Weisheit" auch noch um einiges geringer! Letztens sah ich, dieses treffende Diagramm auf Twitter:
Eckstein:

Du hast Recht, den Junior-Developers würde ich fehlende Erfahrung nicht vorwerfen wollen. Vielleicht ist das Problem ja nicht so groß, wie es sich subjektiv anfühlt. Aber jeder Senior, der noch schlechten Code produziert, hat meiner Meinung nach seine Berufsehre verletzt.

Ich glaube, viele sehen es falsch, und setzen "Erfahrung" mit dem Umfang der Kenntnis aktueller Technologien gleich. Die einzelne Code-Zeilen, die Interface und Methoden werden zum lediglichen Zusammenkleben von Frameworks herunter gehackt. Dabei sind die Basis-patterns und Prinzipien doch die wertvollsten, elementaren "Wahrheiten". Sie bieten doch auch viel mehr Raum für Kreativität und intellektuellen Impuls als das Nachjagen nach fertigen Ideen Anderer!

Hansen:

Okay, siehst du eine Lösung des Desasters?

Eckstein:

Leider nicht in absehbarer Zeit. Die Informatik ist im Bereich der Code-Qualität noch sehr am Anfang. Automatisiert ist es derzeit nur vage möglich Code als gut oder schlecht zu identifizieren. Klar, sollten Qualitäts-Tools, wie Checkstyle, Findbugs und Co, in jedem Projekt die Regel sein. Diese leisten bereits gute Arbeit bei der Verringerung grundlegender Programmierfehler.

Mein Anliegen gilt jedoch der Qualität auf der höheren Schicht, dem Design! Die "weichen" Strukturmerkmale, wie Unveränderlichkeit, Kapselung, die SOLID Prinzipien vor allem, sind noch viel zu unterbewertet! Bei der Automatisierung ist die Wissenschaft hier noch ganz am Anfang. Es kommt immer noch auf die individuellen Fähigkeiten an. Programmiersprachen sind noch nicht weit genug um diese Metaebene zu unterstützen und werden es vielleicht niemals sein.

Liegt es vielleicht in der Natur der Sache? Ist Programmierung ein Handwerk und wird es immer sein, gebunden an den Ausführenden? Dann wäre es eine Kunst? -- Auch keine schlechte Sichtweise!

Hansen:

Lass uns das im Auge behalten! Ich denke das Qualitätsprodukt wird sich immer behaupten!
Kaffee?

Eckstein:

Ja