Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

11

05.03.2015, 16:25

Mir ist gerade beim lesen von Toas Post noch mal aufgefallen: in unserem Projekt wird sehr viel "weggemocket". Das führt dann zu einem dichten Gestrüpp aus XYBuildern, bei denen es länger dauert herauszufinden wie sie funktionieren, als den eigentlichen Test zu schreiben. Die Builder erzeugen ohne entsprechende Methodenaufrufe Objekte im ungültigem Zustand (was sich beim testen dann als Exception äußert, Top Kandidat ist da die NullPointerException).
Für mich ist eine Klasse zustandsbehaftete Logik, die nach außenhin (möglichst immer) gültig bleiben sollte. Die meisten Klassen sehen bei uns aber so aus:

Quellcode

1
2
3
4
5
6
7
8
9
public class Klasse{
  private foo bar = 5;

  getter á la bar = wert; // -> warum bar nicht public machen?
  setter // -> prüft nix und gibt einfach nur bar zurück...

  bisschen Logik hier // -> auch evt. nicht mehr gültig, wer weiß das schon
  bisschen Logik da // -> danach evt. nicht mehr gültig
}

Und das Objekt wird dann rücksichtslos an zig stellen auseinander gebaut, neu zusammen gesetzt, modifziert, usw. als hätten C Progammierer das designed.

Die Builder sind auch schön:

Quellcode

1
Foo testObjekt = new FooBuilder().withWert(1).withAndererWert(2).withWertN("blub").getEntity(); // wenn man davon eine vergisst kann Schrott rauskommen

Ist das in euren Projekten auch so schlimm? Mal unabhängig von der Sprache?

Tobiking

1x Rätselkönig

  • Private Nachricht senden

12

05.03.2015, 16:59

Mir ist gerade beim lesen von Toas Post noch mal aufgefallen: in unserem Projekt wird sehr viel "weggemocket". Das führt dann zu einem dichten Gestrüpp aus XYBuildern, bei denen es länger dauert herauszufinden wie sie funktionieren, als den eigentlichen Test zu schreiben. Die Builder erzeugen ohne entsprechende Methodenaufrufe Objekte im ungültigem Zustand (was sich beim testen dann als Exception äußert, Top Kandidat ist da die NullPointerException).

Es kann sein das euer Mock Framework (falls ihr eins habt, die builder klingen nicht so) einfach zu unintuitiv ist. Die Vorgehensweise das man einen leeren Dummy erzeugt und dann Stubs für die benötigten Funktionen anhängt ist aber üblich. Es soll sogar eine Exception geworfen werden wenn Funktionen aufgerufen werden, die gar nicht aufgerufen werden sollten und entsprechend nicht hinzugefügt wurden.

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

13

05.03.2015, 17:05

Bei uns ist es mit den ungültigen Zuständen zum Glück nicht so schlimm. Dennoch ist die Art, wie das erreicht wird, meiner Meinung nach nicht so sinnvoll.
Beispielsweise gibt es bei uns im Model, also in den Datenklassen, für alles Getter und Setter. Die Setter (vor allem bei Strings) sind so implementiert, dass sie nichts prüfen (kein null-check, obwohl es kaum Member gibt, bei denen ein null Sinn machen könnte), in den Gettern wird dann aber der null-check durchgeführt und notfalls ein Leerstring zurückgegeben.
Alle Arten von Listen (meist ArrayList<T>) sind dabei eine Ausnahme, damit nicht einfach ein null zugewiesen kann, gibt es keinen Setter, sondern nur einen Getter. Den Listen können dann Werte zugewiesen werden, indem die Liste per Getter abgerufen und deren Methoden (add, remove[ic], [ic]clear, ...) aufgerufen werden (statt Methoden, wie "addComment" zu verwenden).
Mit "Datenklassen" meine ich natürlich auch Klassen, die ausschließlich Daten und entsprechende Getter und Setter beinhalten. Da "Im Model keine Logik" sein darf, befinden sich alle möglichen Methoden, die auf irgendeine Weise die Model-Objekte anpassen, in den Managern (früher mal Singletons, jetzt über ServiceLocator abgerufen). Dass nicht ausnahmslos alles in die Model-Klassen geschaufelt werden sollte, ist verständlich und richtig, aber ein Großteil der Dinge, die in den Methoden gemacht wird, gehört eher an andere Stellen.

Und man kann sich doch durchaus für DeKugelschieber freuen, dass in seinem Team automatisierte Tests geschrieben werden. Das ist leider nicht überall der Fall...
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

14

05.03.2015, 17:08

@Tobiking: Es läuft eher so ab dass die Abhängigkeiten des Objekts teils erfüllt sein müssen, für diesen spezifischen Test, andererseite für andere Tests aber nicht.
Dadurch treten Fehler erst an späterer Stelle auf die sich erst recht aufwendig auf das falsch gebaute Objekt zurückführen lässt. Häufig muss immer eine Methode aufgerufen werden. Da frage ich mich warum dies nicht im Konstruktor des Builders der Fall ist.

Die Builder hier machen größtenteils auch nur folgendes:

Quellcode

1
2
3
4
5
new Builder().withWert(123)...

withWert(a){
  neuesObjekt.setA(a);
}

Da wird dann ein Pattern verwendet, nur um ein Pattern zu verwenden...

Ich überspitze vielleicht ein bisschen, trotzdem ist es irgendwie annoying. Und Java trägt auch mal gerne dazu bei.

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

15

05.03.2015, 17:11


Alle Arten von Listen (meist ArrayList<T>) sind dabei eine Ausnahme, damit nicht einfach ein null zugewiesen kann, gibt es keinen Setter, sondern nur einen Getter. Den Listen können dann Werte zugewiesen werden, indem die Liste per Getter abgerufen und deren Methoden (add, remove[ic], [ic]clear, ...) aufgerufen werden (statt Methoden, wie "addComment" zu verwenden).


Das z.B. finde ich gelungenes Design. Ständig wird um Container herumprogrammiert. Aber genau diese Dinge, die ich in meinen privaten Projekten für selbstverständlich erklärt habe, werden hier noch gewrapped, durch ServiceLocater und eine Abstrakte Basisklasse + mehrere Interfaces versteckt/abstrahiert bis zum geht nicht mehr.

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

16

05.03.2015, 17:21


Alle Arten von Listen (meist ArrayList<T>) sind dabei eine Ausnahme, damit nicht einfach ein null zugewiesen kann, gibt es keinen Setter, sondern nur einen Getter. Den Listen können dann Werte zugewiesen werden, indem die Liste per Getter abgerufen und deren Methoden (add, remove[ic], [ic]clear, ...) aufgerufen werden (statt Methoden, wie "addComment" zu verwenden).


Das z.B. finde ich gelungenes Design. Ständig wird um Container herumprogrammiert. Aber genau diese Dinge, die ich in meinen privaten Projekten für selbstverständlich erklärt habe, werden hier noch gewrapped, durch ServiceLocater und eine Abstrakte Basisklasse + mehrere Interfaces versteckt/abstrahiert bis zum geht nicht mehr.

Auf diese Weise ist es aber nicht möglich, die Werte, die der Liste hinzugefügt werden, zu prüfen. Man kann durchaus darüber streiten, welche Prüfungen (maximale Länge bei Strings, kein null) und Einschränkungen (bspw. kein Entfernen von Kommentaren) wohin gehören, meiner Meinung nach sollte aber im Großteil der Fälle nicht einfach eine intern verwendet Liste nach außen weitergereicht werden.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

17

05.03.2015, 17:30

Wenn man will kann man Objekte immer falsch verwenden, komplett ohne zu wissen was man tut geht es sowieso nicht. Daher finde ich das schonmal deutlich besser als jede Operation auf der Liste wieder in Methoden zu wrappen.

Alternativ ginge ja auch sowas:

Quellcode

1
2
3
4
5
6
7
8
9
10
public class Foo extends ArrayList<Integer> { // hier hätte ich mir was wie: "public class Foo extends ArrayList<int>" gewünscht..., naja
  @Override
  public boolean add(int i) {
    if(i > 5 && i < 10){
      return false;
    }

    return super.add(i);
  }
}

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

18

05.03.2015, 17:46

Das geht technisch, ist praktisch aber Mist, weil man eine Komposition nicht durch eine Vererbung ausdrücken sollte. Und nur für Konsistenzprüfung ständig eine Unterklasse einzuführen ist auch sehr unschön.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

19

05.03.2015, 18:26

Man kann Objekte falsch verwenden, aber sie sollten so aufgebaut sein, dass das so schwer wie möglich ist.
Abgesehen davon kann es für Außenstehende auch, abhängig vom Anwendungsfall, eventuell einfach egal sein, wie die interne Repräsentation aussieht, ob also ein Array oder eine Liste verwendet wird, ob Kommentar-, UserContent- oder String-Objekte verwendet werden.

Und BlueCobold hat ja schon geschrieben, dass diese Erweiterung des Arrays nicht gerade gut ist. Spätestens, wenn eine Prüfung durchgeführt werden muss, die auf dem Wert eines anderen Members (nicht der Liste) beruht, wird wieder eine Referenz auf das Objekt benötigt, das diese Liste beinhaltet. Auch wenn man das mit inneren Klassen machen kann, zeigt das, dass das absolut nichts mit Wiederverwendbarkeit zu tun hat. Entsprechend wäre es sinnvoller, nach außen hin nur die Operationen anzubieten, die zugelassen sind.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

20

05.03.2015, 20:13

Ich stimme euch voll zu. Es hängt wohl vom Anwendungsfall ab. Gemeint war auch kein generelles herausreichen von ArrayListen, aber wenn es sinnvoll ist schöner als jede Methode dieser nachzubauen und durchzureichen :)

Werbeanzeige