# Was zeichnet einen erfahrenen Softwareentwickler aus ? Was kann man nach 6 Monaten erwarten ? ?



## jhjh (14. Mrz 2019)

Hallo,
ich beschäftige mich seit ca 8 Monaten mit Java. In einem Praktikum habe ich mir ca. 1 - 1/2 Monate Grundkenntnisse in Java angeeignet. Ich muss sagen, dass ich davor auch schon mit Programmierung in Berührung kam (VBA , JavaScript), allerdings hatte ich mit OOP noch nicht viel zu tun. Das war dann eher von Theoretischer Natur in meinem Studium.
Nun befinde ich mich am Ende meines Studium und Gegenstand meiner Abschlussarbeit ist die Entwicklung einer Android Applikation (schon so gut wie fertig). Hierfür habe ich gut 6 Monate gebraucht (inkl. einstieg in die Android Entwicklung).
Das Design meiner Software würde ich als "Nicht Schlecht" einstufen. Ich denke so manches hätte ich auch anders / einfacher machen können, aber im Groben würde ich sage, dass es erstmal "OK" ist. Möglicherweise hätte ich mich zu begin ein wenig mit Design Pattern beschäftigen können / sollen. Worauf ich besonders Wert gelegt habe:

- Sinnvolle Namen (Variablen, Methoden, Klassen)
- Auslagerung von Code in Klassen / Methoden
- Kein oder sehr wenig redudanter Code
- Kommentare dort wo es nötig ist

Mich würde jetzt mal interessieren was man nach 8 Monaten erwarten kann ? Was unterscheidet einen Unerfahrenen (definiere jetzt 8 Monate mal als "Unerfahren") von einem Erfahrenen Entwickler (> 5 Jahre Entwickler) bzgl der Herangehensweise an Software Projekten. Ich schätze mal man erkennt normalerweise am Code ob es sich hier um einen Erfahrenen oder Unerfahrenen Entwickler handelt. Wie war das bei euch ? Was habt ihr nach paar Jahren anders gemacht als zu Begin (z.B. das erste Projekt).

Manchmal denke ich halt, ich werde nie fertig, weil ich immer nach Möglichkeiten suche um etwas noch ein Stückchen besser machen möchte. Dann denke ich aber manchmal "Ach sch... drauf, es ist dein erste etwas größeres Projekt, das passt schon so..."


----------



## httpdigest (14. Mrz 2019)

Erfahrung bedeutet im Großen und Ganzen schlicht, dass du mehr Frameworks/Libraries/Techniken kennenlernst und einzuschätzen lernst, wann du diese einsetzen kannst/solltest, um das Rad nicht neu zu erfinden. Deine Toolbox erweitert sich mit der Zeit. Kennst du jetzt noch Java und Android bzw. das Android SDK, kennst du morgen die Stream API von Java, übermorgen Gradle/Maven, danach Spring und dann einige der vielen Apache Libraries (nicht notwendigerweise in dieser Reihenfolge). Und das war vielleicht nur 1% dessen, was ein erfahrener Java-Entwickler in seinem Leben alles kennengelernt hat.
Hinzu kommen dann noch diverse andere eher DevOps Tools wie Umgang mit Buildservern wie Travis/Jenkins oder dem AWS/GCP/Azure Ökosystem, um größere Systeme/Anwendungslandschaften/Architekturen in der Cloud zu designen.
Du siehst dann, wie Dinge dort umgesetzt werden oder wie Dinge mithilfe dieser Tools/Libraries/Frameworks umgesetzt werden und passt deine eigene Sichtweise entsprechend an.
Dein Horizont erweitert sich ständig.

Ein wesentlicher Unterschied vielleicht noch zwischen einem unerfahrenen und einem erfahrenen Entwickler:
Der unerfahrene Entwickler versucht, gleich alles von Anfang an richtig zu machen, zu polieren und ein eher "statisches" Qualitätsmaß für seine Software zu haben.

Der erfahrene Entwickler weiß, dass sich Software ständig und in unvorhergesehener Weise ändern wird. Er versucht deshalb, die Stellen, die sich vermutlich schnell/leicht ändern, stärker vom Rest des Systems zu abstrahieren und änderbar zu halten. Die Stellen, die sich wohl weniger stark ändern werden und zusammengehören, werden so kohäsiv und einfach wie möglich realisiert. Er vertritt eher eine "Design for Change" Philosophie.
Je erfahrener du wirst, desto eher weißt du, welche Teile sich vermutlich eher schnell ändern werden und welche Teile sich weniger ändern werden. Du lernst, fachliche Anforderungen, die an eine Software gestellt werden, entsprechend einzuschätzen.


----------



## jhjh (14. Mrz 2019)

Danke erstmal!


> Der unerfahrene Entwickler versucht, gleich alles von Anfang an richtig zu machen, zu polieren und ein eher "statisches" Qualitätsmaß für seine Software zu haben.
> 
> Der erfahrene Entwickler weiß, dass sich Software ständig und in unvorhergesehener Weise ändern wird. Er versucht deshalb, die Stellen, die sich vermutlich schnell/leicht ändern, stärker vom Rest des Systems zu abstrahieren und änderbar zu halten


Ja, das merke ich besonders bei der Android Entwicklung. Gefühlt sind 10 % meines Codes nach einer neuen Android Version nicht mehr zu gebrauchen 



> "Design for Change" Philosophie


Ich hätte mal während meiner Entwicklung eine "Design for Testing" Philosophie verfolgen sollen! 
Ich habe einen JUnit Test für eine ziemlich triviale Sache gehalten, aber dem ist wohl nicht so ....


----------



## M.L. (14. Mrz 2019)

> "Design for Testing" Philosophie


Da könnte das Stichwort TDD weiterhelfen: https://de.wikipedia.org/wiki/Testgetriebene_Entwicklung


----------



## mihe7 (14. Mrz 2019)

jhjh hat gesagt.:


> Ich habe einen JUnit Test für eine ziemlich triviale Sache gehalten, aber dem ist wohl nicht so ....


Naja, der Test selbst ist trivial: Eingabe -> Ausgabe == erwartete Ausgabe? Der Punkt dabei ist: Dein Code muss so geschrieben sein, dass solche Tests erst möglich werden.


----------



## jhjh (14. Mrz 2019)

> Da könnte das Stichwort TDD weiterhelfen: https://de.wikipedia.org/wiki/Testgetriebene_Entwicklung


https://de.wikipedia.org/wiki/Testgetriebene_Entwicklung
Ja das ist für mein nächstes Projekt sicherlich hilfreich 


> Der Punkt dabei ist: Dein Code muss so geschrieben sein, dass solche Tests erst möglich werden.


Ja und das wird an manchen Stellen bei mir problematisch 
Aber evtl. auch garnicht so tragisch, da der Sinn eines JUnit Test ja nicht darin besteht JEDE Methode einer Klasse zu testen ? Mein Vorhaben ist, dass Methoden die...
-> eher selten und nur unter bestimmten Bedingungen aufgerufen werden
-> etwas komplexer sind 
-> einen Rückgabewert haben
... zu testen.
 Oder nach welchen Kriterien sollte ich vorgehen ?


----------



## httpdigest (14. Mrz 2019)

Getestet wird gegen die Schnittstelle einer Klasse.
Eine Klasse hat üblicherweise eine Verantwortlichkeit, also soll eine und nur eine bestimmte Aufgabe haben. Hier kommen wir auch langsam in das Gebiet von den S.O.L.I.D. Prinzipien. Die kannst du dir auch noch angucken.
Gemäß "Information Hiding" und "Encapsulation" sollte eine Klasse eine öffentliche Schnittstelle und private Interna haben. Gegen ersteres werden Tests formuliert. Gegen letzteres nicht.
Das hat nichts damit zu tun, wie komplex eine Methode ist oder wie selten sie aufgerufen wird.


----------



## mihe7 (14. Mrz 2019)

jhjh hat gesagt.:


> Aber evtl. auch garnicht so tragisch, da der Sinn eines JUnit Test ja nicht darin besteht JEDE Methode einer Klasse zu testen


Nein. Es ergibt sich beim TDD praktisch automatisch, was zu testen ist, weil Du "ständig" am umstrukturieren bist. In der Regel ist die Methode dann private und wird von einer public-Methode aus erreicht und getestet oder Du erstellst eine neue Klasse, die dann Gegenstand eigener Tests ist.


----------



## jhjh (14. Mrz 2019)

> sollte eine Klasse eine öffentliche Schnittstelle


Liegt hier die Betonung auf *eine *?
Da eine Klasse ja mehrere öffentliche Schnittstellen bzw. mehrere öffentliche Methoden besitzen kann. Heißt ich müsste dann gegen jedes dieser öffentlichen Schnittstellen testen !?




> Gemäß "Information Hiding" und "Encapsulation" sollte eine Klasse eine öffentliche Schnittstelle und private Interna haben. Gegen ersteres werden Tests formuliert.
> Das hat nichts damit zu tun, wie komplex eine Methode ist oder wie selten sie aufgerufen wird.



Ich habe mich bzgl. JUnit bisher hieran etwas orientiert
https://zeroturnaround.com/rebellab...ight-methods-for-unit-testing-your-java-apps/
Hier heißt es dann u. A.


> *What you should NOT test*
> ......
> ......
> 2. The database (you should assume it works correctly when it is available)
> ...


Das wäre ja dann ein wenig widersprüchlich mit dem was du sagst ? Oder verstehe ich das falsch ? 
 Da beispielsweise Getter-Methoden ja üblicherweise öffentliche Schnittstellen sind. Eine Datenbank Klasse ist ja in der Regel auch eine öffentliche Schnittstelle.



> In der Regel ist die Methode dann private und wird von einer public-Methode aus erreicht und getestet


Aber wie schaut es mit folgendem Fall aus (keine public-Methode)
1. Activity A startet Activity B über ein Intent

```
protected void onCreate(Bundle savedInstanceState) {
    ...
    ...
    privateMethode();
   ....

   void private Methode(){
   ...
  }
}
```


----------



## httpdigest (14. Mrz 2019)

jhjh hat gesagt.:


> Da beispielsweise Getter-Methoden ja üblicherweise öffentliche Schnittstellen sind.


Das stimmt. Getter und Setter bzw. triviale Methoden brauchen nicht getestet zu werden, da hier angenommen wird, dass bei dessen Implementierung keine Fehler gemacht werden. Zumal das durch Tools wie IDE-auto-generierte Getter/Setter oder Lombok noch weiter sichergestellt werden kann.
Was sie mit "Datenbank nicht testen" meinen ist, dass du eben keinen Code testen brauchst, den du nicht selbst geschrieben hast. Externer Code von Drittanbietern (also nicht von dir selbst) nimmst du als korrekt an.
Die "Unit under Test" ist dann natürlich nicht die Datenbank oder eine Schnittstelle zur Datenbank, sondern nur deine eigenen Klassen.



jhjh hat gesagt.:


> Eine Datenbank Klasse ist ja in der Regel auch eine öffentliche Schnittstelle.


Erstmal ist eine Datenbank keine Klasse. Eine Datenbank _kann_ über eine API (die in Form von Klassen realisiert ist) an deine Anwendung angebunden sein. Und dann stellt diese API eben über Klassen eine Schnittstelle zur Datenbank selbst bereit. Da du aber die Datenbank selbst nicht testet, formulierst du entsprechend dann ja auch keine Tests gegen diese Schnittstelle.


----------



## mihe7 (14. Mrz 2019)

jhjh hat gesagt.:


> Aber wie schaut es mit folgendem Fall aus (keine public-Methode)


Beim UI verhält es sich wie bei der DB: nicht im Unit-Test. Im konkreten Fall handelt es sich um eine Implementierung einer Methode, die von einem Framework zur Verfügung gestellt und aufgerufen wird. Das Problem dabei: ohne das Framework kannst Du das nicht (sinnvoll) testen.

Man muss verstehen, dass es beim TDD nicht wie beim klassischen Test darum geht, Fehler zu finden, sondern vielmehr darum, die Anwendung so zu strukturieren, dass sie testbar ist. 

Es kommt also darauf an, was Du in Deiner privaten Methode machst: falls es dort nur ums UI geht -> vergiss es (oder schreib Dir einen UI-Test; der wird in Android dann auf dem Gerät/Emulator ausgeführt). Geht es dort aber um Logik, dann hat die in der Activity nichts verloren -> in eine Klasse auslagern und dort testen. In Deiner Activity bindest Du dann die Klasse ein. Das ist meine persönliche Meinung, es gibt Leute, die das anders sehen


----------



## mrBrown (14. Mrz 2019)

jhjh hat gesagt.:


> Da eine Klasse ja mehrere öffentliche Schnittstellen bzw. mehrere öffentliche Methoden besitzen kann. Heißt ich müsste dann gegen jedes dieser öffentlichen Schnittstellen testen !?


"Eine Schnittstelle" kann mehrere Methoden umfassen 



httpdigest hat gesagt.:


> Das stimmt. Getter und Setter bzw. triviale Methoden brauchen nicht getestet zu werden, da hier angenommen wird, dass bei dessen Implementierung keine Fehler gemacht werden. Zumal das durch Tools wie IDE-auto-generierte Getter/Setter oder Lombok noch weiter sichergestellt werden kann.


Wobei man sie nahezu immer "nebenbei" mit-testet. Wenn man sie in den Tests nicht braucht, braucht man sie meist gar nicht (und nach TDD ohne "meist").


----------



## jhjh (14. Mrz 2019)

> Was sie mit "Datenbank nicht testen" meinen ist, dass du eben keinen Code testen brauchst, den du nicht selbst geschrieben hast. Externer Code von Drittanbietern (also nicht von dir selbst) nimmst du als korrekt an.


Ich verstehe, Danke! 


> Geht es dort aber um Logik, dann hat die in der Activity nichts verloren


Hmm, also ich habe beispielsweise eine _GoogleMapActivity. _Hier habe ich sämtliche Methode wie beispielsweise
-> Setzen/Löschen/Verschieben von Markern
-> Circle Objekt eines Markers vergrößern/verkleinern
-> Bestimmte Linien erstellen
etc...
Deiner Meinung würde dann sowas eher nicht in die Activity gehören ? Unabhängig vom Testen mein ich.



> "Eine Schnittstelle" kann mehrere Methoden umfassen


Moment mal, bin ein wenig verwirrt  Also mit "Schnittstelle" ist doch hiermit kein Interface im klassischen Sinne gemeint ? Dass ein Interface mehrere Methode beinhalten kann, weiß ich. Aber hier geht es ja um die "Internen Klassen Schnittstellen" ... Also sowas wie _getKunde ()_. Wenn ich also deine Aussage versuche zu übersetzen...
_-> Eine Schnittstelle, wie beispielsweise getKunde(), kann mehrere Methoden umfassen
...würde das ja keinen Sinn ergeben _


----------



## mrBrown (14. Mrz 2019)

jhjh hat gesagt.:


> Hmm, also ich habe beispielsweise eine _GoogleMapActivity. _Hier habe ich sämtliche Methode wie beispielsweise
> -> Setzen/Löschen/Verschieben von Markern
> -> Circle Objekt eines Markers vergrößern/verkleinern
> -> Bestimmte Linien erstellen
> ...


Jein.
Das ganze ist natürlich auch GUI-Kram, der gehört in die Activity - zb welcher Marker grad verschoben wird
Das ganze ist aber nicht nur GUI-Kram, und das was keine GUI mehr ist, gehört nicht in die Activity - zB, wo welcher Marker ist und wo welche Linie.



jhjh hat gesagt.:


> Moment mal, bin ein wenig verwirrt  Also mit "Schnittstelle" ist doch hiermit kein Interface im klassischen Sinne gemeint ? Dass ein Interface mehrere Methode beinhalten kann, weiß ich. Aber hier geht es ja um die "Internen Klassen Schnittstellen" ... Also sowas wie _getKunde ()_. Wenn ich also deine Aussage versuche zu übersetzen...
> _-> Eine Schnittstelle, wie beispielsweise getKunde(), kann mehrere Methoden umfassen
> ...würde das ja keinen Sinn ergeben _


Schnittstelle umfasst eine Menge von Methoden (und theoretisch auch Feldern), die von außen sichtbar sind. Die kann natürlich auch nur ein Element haben, aber eben auch mehrere.

getKunde() wäre vermutlich eher Teil der Schnittstelle (die dann u.U. noch sowas wie setKunde hat). Es kann natürlich auch allein die Schnittstelle sein, ob das sinnvoll ist, hängt von dem spezifischen Fall ab.


Analog zur echten Welt: deine Tastatur ist eine Schnittstelle zu deinem Rechner, und die Tastatur hat mehrere Tasten. Man könnte aber natürlich auch eine einzelne Taste als Schnittstelle haben (wie zB ein Telegraf).

(BTW, "Interne Klassen Schnittstellen" gibts nicht, entweder es ist intern oder eine Schnittstelle )

Ein Java-Interface ist bei der Betrachtung nur ein Spezialfall einer Klasse, nämlich eine mit nur öffentlichen, abstrakten Methoden (bis Java 8, macht's in der Betrachtung leichter). Im anderen Sprache gibts zT keine gesonderten Interfaces, sondern nur Klassen (oder sogar nur Objekte), die haben aber natürlich trotzdem eine Schnittstelle.


----------



## jhjh (14. Mrz 2019)

> Analog zur echten Welt: deine Tastatur ist eine Schnittstelle zu deinem Rechner, und die Tastatur hat mehrere Tasten. Man könnte aber natürlich auch eine einzelne Taste als Schnittstelle haben (wie zB ein Telegraf).


Ja an sich verstehe ich das, aber Codetechnisch ist mir das nicht so ganz klar. Hast du villeicht ein Beispiel ?


----------



## mihe7 (14. Mrz 2019)

Nimm z. B. eine Liste: Du kannst Elemente in die Liste einfügen, Du kannst sie anfügen, Du kannst sie löschen usw. Das ist die Schnittstelle (z. B. java.util.List). Diese sagt nichts darüber aus, wie das technisch implementiert wird: eine ArrayList verwendet intern ein Array, eine LinkedList verkettete Elemente. Daraus ergeben sich unterschiedliche Eigenschaften (wie z. B. unterschiedliche Laufzeiten beim Einfügen).


----------



## mihe7 (14. Mrz 2019)

jhjh hat gesagt.:


> Deiner Meinung würde dann sowas eher nicht in die Activity gehören ?


Wie @mrBrown schon geschrieben hat, hängen hier ja zwei Dinge dran.

Am besten wir machen mal ein Beispiel: TicTacToe. Das ist etwas, an dem sich Anfänger hier im Forum gerne mal versuchen. Oft wird das so implementiert, dass Buttons verwendet werden, um das Spielfeld darzustellen. Am Anfang haben diese Buttons keinen Text. Wenn jemand draufklickt, wird der Text entweder auf ein X oder auf ein O geändert usw. An irgendeiner Stelle kommt es dann zu einem Problem, dann wird der Code hier gepostet und es trifft einen halb der Schlag 

Der Fehler dabei ist, dass das UI, der "Spielstand" und die Spiellogik zu einer Einheit verschmolzen wird.

Wenn Du den Spielstand (Logik) in eigene Klassen verlagerst, dann ist dieser Unit-testbar. Und weil die Logik jetzt separat existiert, kannst Du sie auch wiederverwenden. Dann kannst Du beispielsweise die 3TGE ("Tic Tac Toe Gaming Engine" ) verwenden, um ein Android-, Swing-, Web-, JavaFX-, OpenGL-, SWT-, ...-UI dranzuhängen.


----------

