Programmflow-Optimierung

CHAOSFISCH

Bekanntes Mitglied
Servus,

ich bräuchte mal ein wenig Hilfe bei der Optimierung des Programmflows einer Klasse.
Es handelt sich hier um ein FileUploader, daher kann das ganze relativ gut aufgeteilt werden in einzelne Segmente. Allerdings muss der Datei-Upload resumeable sein. Das funktioniert soweit alles, arbeitet jedoch nicht mit optimalem flow. So werden exceptions für die Steuerung (an gewissen Stellen) genutzt - was an und für sich nicht gemacht werden sollte.

Die Datei ist vom Programmcode zu lang zum Posten, zu finden im Git-Rep.: UploadWorker.java - simple-java-youtube-uploader - Youtube Uploader by CHAOSFISCH - Google Project Hosting

Im Anhang ist ein kurzer Ansatz wie es ablaufen sollte.
Z.B. ist mir unklar wie ich bei einem Fehler wieder nach oben springen kann (z.B. zur Autentifizierung) ohne dabei eine exception auszulösen. Und: wenn ich dann dort drinnen wieder bin, wie kommt das Programm zurück zum jeweiligen nächsten Schritt.
Bsp:
Man ist in Schritt 3 -> Fehler -> 1 -> 3.

Soll ich dann einfach eine flag setzen, dass Schritt 2 fertig ist? Was ist bei einem Programmflow dann aber mit 10 Schritten. Dann bräuchte ich 10 Flags. Das führt langfristig zu einer Speichervergeudung. Sollte ich hier also quasi mit States arbeiten (also: State authentication, S. Metadata, S. Upload) ?

Gruß
CHAOSFISCH
 

Anhänge

  • Uploadworker-Programpath.jpg
    Uploadworker-Programpath.jpg
    42,9 KB · Aufrufe: 44

CHAOSFISCH

Bekanntes Mitglied
Mh, da mir anscheinend noch keiner richtig helfen konnte versuche ichs mal mithilfe von einem Codebeispiel. Dies sollte leichter verständlich sein, als sich die komplette vorhandene Klasse anschauen zu müssen.

Java:
public class CodeExampleUploadWorker
{
	public enum STATUS
	{
		AUTHENTICATION, METADATA, UPLOAD, POSTPROCESS, DONE, FAILED, ABORTED
	}

	public STATUS currentStatus;
	public STATUS lastStatus = STATUS.METADATA;

	public void background()
	{
		//Einstiegspunkt in diesen Thread.
		/* Abzuarbeiten sind mehrere Teilschritte, jeder Schritt kann jedoch fehlschlagen und muss wiederholbar sein. */
		while (!(currentStatus.equals(STATUS.ABORTED) || currentStatus.equals(STATUS.DONE) || currentStatus.equals(STATUS.FAILED))) {
			switch (currentStatus) {
				case AUTHENTICATION:
					//Schritt 1: Auth
					authenticate();
					break;
				case METADATA:
					//Schritt 2: MetadataUpload + UrlFetch
					metadata();
					break;
				case UPLOAD:
					//Schritt 3: Chunkupload
					upload();
					break;
				case POSTPROCESS:
					//Schritt 4: Postprocessing
					postprocess();
					break;
			}
		}
	}

	private void postprocess()
	{

	}

	private void upload()
	{
		//solange bytes zum uploaden
		while (true) {
			//code für den chunkupload
		}
	}

	private String metadata()
	{
		return "URL";
	}

	private boolean authenticate()
	{
		return true;
	}
}

Wenn ein Schritt fertig ist, so setzt er den neuen "currentStatus" eins weiter und setzt den "lastStatus" neu. Warum lastStatus: Ich sehe keine andere Möglichkeit bei einem Fehler im upload() -> aufruf der neuen Auth -> upload() dies so zu verbinden.

Ansonsten tipps gerne.
 

Ullenboom

Bekanntes Mitglied
Das klingt für mich auch wie in Zustandsautomat, hier gibt es auch ganz unterschiedliche vorgefertigte Frameworks. Doch das selbst zu machen wie in deinem Code ist doch völlig Ok. Vielleicht ist noch interessant, dem enum Methoden zu geben wie process(Context cnx), angelehnt aus dem Beispiel hier:

Java:
public enum GameCurrency
{
  EURO() {
    @Override double convertTo( GameCurrency targetCurrency, double value )
    {
      return targetCurrency == EURO ? value : value / 2;
    }
  },
  PONRODOLLAR() {
    @Override double convertTo( GameCurrency targetCurrency, double value )
    {
      return targetCurrency == PONRODOLLAR ? value : value * 2;
    }
  };

  abstract double convertTo( GameCurrency targetCurrency, double value );
}
Statt convertTo() heißt es bei dir dann process() und es wird ein Context übergeben. Der könnte dann den aktuellen Zustand enthalten und die Enums-Methoden dann einfach die Operation ausführen und "weiterschalten".
 
N

nillehammer

Gast
Ich würde aus Deinen Methoden heraus durchaus Exceptions schmeißen, wenn ein Fehler auftritt. Exceptions sind nun mal in Java der Weg der Wahl, um Fehler zu melden. Von speziellen return-Codes halte ich in dem Zusammenhang überhaupt nichts. Du kannst in der while-Schleife einen try-catch-Block einbauen und im catch-Teil die Excetion loggen und danach ein continue machen.
 
S

SlaterB

Gast
Workflow ist wohl noch eher der Fachbegriff, falls nicht bekannt (hier bisher nicht genannt worden),
da kann man riesige komplizierte Systeme zusammenbauen

wenn du 10 Schritte hast, dann vielleicht auch 10 Einträge, 10 Objekte, jeweils mit einem boolean, Verknüpfung zu Vorgänger, Nachfolger usw.,
wenn du von einem dieser Schritte zu AUTHENTICATION musst, dann könntest du einen neuen derartigen Eintrag erstellen und als 'Unterbrechung' anhängen, Baumstruktur, könnte theoretisch selber noch weiter unterbrochen/ strukturiert werden,
falls es aber fertig ist, dann kann am Workflow-Graphen erkannt werden, wo es danach weitergeht, ohne einen zentralen einzeln begrenzen "lastStatus"

-----

Exception-Steuerung halte ich für so komplexe Sprünge gar nicht mal abwegig,
je nach Aufbau vielleicht aber nicht nötig,
habe mir deine Klassen nicht angeschaut, wenn man sich aber die background()-Methode mit der Schleife anschaut,
dann hast du eine schöne zentrale Stelle, aus der die Untermethoden eine Information zum Abbruch zurückgebenen können
(falls nicht schon im Workflow-Graph einbaut), dann könnte diese zentrale Stelle im nächsten Schleifendurchlauf auf AUTHENTICATION wechseln usw.,

denkbar dass es ohne Exceptions auskommt, "Z.B. ist mir unklar wie ich bei einem Fehler wieder nach oben springen kann" scheint nicht mehr so aktuell


--------

das vorerst lose eingeworfen ;)
 

CHAOSFISCH

Bekanntes Mitglied
Ich würde aus Deinen Methoden heraus durchaus Exceptions schmeißen, wenn ein Fehler auftritt. Exceptions sind nun mal in Java der Weg der Wahl, um Fehler zu melden. Von speziellen return-Codes halte ich in dem Zusammenhang überhaupt nichts. Du kannst in der while-Schleife einen try-catch-Block einbauen und im catch-Teil die Excetion loggen und danach ein continue machen.

Ja, das weiß ich. Allerdings ist es auch so, dass es in diesem Zusammenhang nicht wirklich ein Best-Practice gibt mit den Exceptions. Soll eine Exception wirklich zur Programmflusssteuerung genommen werden oder sollten Exceptions nicht wirklich eine "Ausnahme" darstellen. Das eine Auth. nicht klappt, damit muss man eigentlich immer rechnen - von daher ist die Frage: macht dann hier eine Exception wirklich Sinn um die Auth zu wiederholen.

Wie dem auch sei - man kann sicher beides machen.
Habe allerdings auch die Erfahrung mittlerweile, dass ein Workflow mit begrenzter Verwendung von Exceptions irgendwie hier geeigneter sein könnte. Warum: (gut der Code ist bei weitem nicht optimal) Ich hatte Probleme das User-Event Abbruch zu verarbeiten. Der Upload stoppte einfach nicht, weil in der ersten Schleife dann die 2. Schleife kam. Selbst mit einer Exception konnte ich nicht wirklich nach oben durchbrechen an die Stelle wo abbgebrochen werden sollte. Ich musste halt dann eine neue ExceptionKlasse definieren. Diese wurde in der 1. Schleife aufgefangen und dann ignoriert - nur damit das Programm quasi in die 1. Schleife zurückkommt. Das finde ich doch schon irgendwie sehr sinnfrei und ein Fehler im Workflow.

D.h. allein die doppel while Schleife, auch im Beispielcode ist falsch - soll nur eine sein.

wenn du 10 Schritte hast, dann vielleicht auch 10 Einträge, 10 Objekte, jeweils mit einem boolean, Verknüpfung zu Vorgänger, Nachfolger usw.,
wenn du von einem dieser Schritte zu AUTHENTICATION musst, dann könntest du einen neuen derartigen Eintrag erstellen und als 'Unterbrechung' anhängen, Baumstruktur, könnte theoretisch selber noch weiter unterbrochen/ strukturiert werden,
falls es aber fertig ist, dann kann am Workflow-Graphen erkannt werden, wo es danach weitergeht, ohne einen zentralen einzeln begrenzen "lastStatus"
D.h. (verstehe ich dich richtig) Wenn ich zum enum aus dem Beispielcode noch weitere States einfüge wie z.B. UPLOAD_AUTHENTICATION und falls dann der Fall eintritt, dass eine neue Auth. während des uploads notwendig wird, dann wird der Status auf UPLOAD_AUTH. gesetzt. Das Programm erkennt daran, dass es wieder zum Status UPLOAD springen muss und kann so fortsetzen.
 
S

SlaterB

Gast
D.h. allein die doppel while Schleife, auch im Beispielcode ist falsch - soll nur eine sein.
warum im upload() eine Schleife ist, ist nicht zu erkennen,
scheint kaum mit dem Workflow an sich zu tun haben, dann sicher niötig

D.h. (verstehe ich dich richtig) Wenn ich zum enum aus dem Beispielcode noch weitere States einfüge wie z.B. UPLOAD_AUTHENTICATION und falls dann der Fall eintritt, dass eine neue Auth. während des uploads notwendig wird, dann wird der Status auf UPLOAD_AUTH. gesetzt. Das Programm erkennt daran, dass es wieder zum Status UPLOAD springen muss und kann so fortsetzen.

unterschiedliche Enum sind ziemlich statische Sache, vergleichbar mit den von dir genannten 10 boolean,
wenn in anderen Schritten auch AUTHENTICATION drankommen kann dann noch mehr Enums usw.,
das war nicht mein Vorschlag

ich sprach vor allem von dynamischen Baum, das ein bestimmtes Objekt im Workflow, welches vielleicht einen Enum-Wert UPLOAD hat, sonst aber einen individuellen Zustand, eine Information 'hier Unterbrechung zu xy' bekommt,
und ich meinte zudem, dass dieses xy nicht unbedingt der schon bekannte erste Schritt sein muss,
sondern ein neues Objekt, welches auch AUTHENTICATION ist, sich aber vom 1., schon bearbeiteten Schritt aus den originalen 10 unterscheidet
 

CHAOSFISCH

Bekanntes Mitglied
warum im upload() eine Schleife ist, ist nicht zu erkennen,
scheint kaum mit dem Workflow an sich zu tun haben, dann sicher niötig



unterschiedliche Enum sind ziemlich statische Sache, vergleichbar mit den von dir genannten 10 boolean,
wenn in anderen Schritten auch AUTHENTICATION drankommen kann dann noch mehr Enums usw.,
das war nicht mein Vorschlag

ich sprach vor allem von dynamischen Baum, das ein bestimmtes Objekt im Workflow, welches vielleicht einen Enum-Wert UPLOAD hat, sonst aber einen individuellen Zustand, eine Information 'hier Unterbrechung zu xy' bekommt,
und ich meinte zudem, dass dieses xy nicht unbedingt der schon bekannte erste Schritt sein muss,
sondern ein neues Objekt, welches auch AUTHENTICATION ist, sich aber vom 1., schon bearbeiteten Schritt aus den originalen 10 unterscheidet

Ja, da haste recht. Mein Gehirn denkt aber auch heute langsam, dass wäre dann ja wieder so statisch.
Ich muss das mal aufräumen - jetzt gleich.
 

Ähnliche Java Themen

Neue Themen


Oben