Ich wollte mal kurze Frage zum Design des Codens stellen.
Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.
Jetzt möchte ich dazu programmieren, dass die Daten nur geschickt
werden, wenn sie sich auch wirklich geändert haben.
Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe
ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich
ist.
Was ist der gängige Programmierstil?
Fragender schrieb:> Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe> ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich> ist.
Das kommt darauf an. Wie heißt die Funktion, was gibt sie vor zu tun,
wie ist sie dokumentiert, was würde der Leser spontan erwarten wenn er
das sieht, wie verhalten sich ähnliche Funktionen in anderen Teilen
deines Codes, ist es naheliegend es so zu tun, wird es einfacher lesbar,
führt es insgesamt zu weniger code?
Fragender schrieb:> ....> Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.> Jetzt möchte ich dazu programmieren, dass die Daten nur geschickt> werden, wenn sie sich auch wirklich geändert haben.> Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe> ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich> ist.> Was ist der gängige Programmierstil?
Mit anderen Worten: Du willst die function aufrufen und dann in der
function prüfen ob sie was machen soll?
Ruf die function dann auf, wenn Du sicher bist dass Du sie brauchst!
wenn nur bei Änderung gesendet wird macht das Initialisierungen und
Diagnosen schwer.
i.d.R gibt es dann eine mindeste und einen maximale Updaterate.
Was es immer geben sollte ist ein aussagekräftiger Betreff
Wenn es Dir irgendwie falsch vorkommt dann ist es wahrscheinlich falsch.
Oder falsch dokumentiert. Oder falsch benannt. Scheib es so hin daß es
offensichtlich wird und sich richtig anfühlt.
Wenn die Funktion in etwa "writeData()" heißt, würde ich als
Außenstehender erwarten, dass die Daten immer geschrieben werden, sobald
ich die Funktion aufrufe. "updateData()" oder "writeNewData()" klingen
für mich eher so, dass nur geänderte Daten geschrieben werden.
Je, nachdem, wie oft welcher Fall benötigt wird (alle Daten schreiben
oder nur Neue) könnte man der writeData() eine Wrapper-Funktion
schreiben, die dann eben writeData() nur aufruft, wenn neue Daten da
sind. Was natürlich wieder Sprünge und Zeit braucht.
Insgesamt ist es nicht festgelegt, wie man es umsetzt. Es sollte nur für
andere ersichtlich sein, was eine Funktion tut.
Fragender schrieb:> Was ist der gängige Programmierstil?
Je nach Komplexität kannst Du da auch 3 Funktionen draus machen:
- Eine die Sendet
- Eine die Daten vergleicht
- und eine, die Daten vergleicht und Kopie / Hash der Daten erstellt und
sendet.
Fragender schrieb:> Was ist der gängige Programmierstil?
Als Gelegenheitsprogrammierer hat das imo mit Stil wenig zu tun sondern
mit Funktion.
Meiner einer bildet in der Software die Funktion ab (soweit möglich).
Wenn das "nichtsenden" zum senden gehört (z.B. zum Stromsparen) mache
ich es da, gehört es zu den Daten (Gegenseite erwartet nur geänderte
Daten) prüfe ich da.
Man kann natürlich auch eine extra Funktion schreiben und danach bedingt
aufrufen. Das würde ich machen wenn es wichtig wäre und auffallen soll.
Ja,
Je nach verwendeter Struktur (ist es ein µC oder eine PC-Anwendung oder
die Steuerung eines Flugzeuges) gibt es halt mehrere Kriterien an Hand
derer du deine Auswahl treffen kannst.
Wenn das schreiben (oder Daten speichern...) zB innerhalb einer
Interrupt Routine läuft, macht es Sinn das kontrollieren außerhalb und
als eigene Funktion zu beschreiben.
etc. [beliebeige Beispiele]
In den meisten Anwendungen würde ich in der Konfiguration einen Flag
setzen um diese Optimierung ein/ausschalten zu können (Testen /
Fehlersuche) und bei Aktivierung das letzte gesendete Datenpaket immer
im Speicher mit dem neuen Vergleichen vor jedem senden.
ausserdem schrieb:> Sorry, ich bin kein fernsehgucker. Musste erst Wikipedia fragen, was 42> bedeutet. Kryptisches mit Kryptischem erklären? Hilft das?
Zur 42: https://de.wikipedia.org/wiki/Per_Anhalter_durch_die_Galaxis
Was dir der Schreiber damit sagen wollte: Ohne
ein paar Code-Schnipsel ist es sehr schwer, darauf
eine Antwort zu geben. Warum schreibst du den
Code nicht so hin, wie du denkst und fragst uns
dann hier um unsere Meinung? Wäre einfacher.
merciless
/* Send data to a lower software module which performs the actual sending of data. */
45
}
46
[...]
47
}
BTW: Wenn du eine Frage so hineinwirfst, kommen ganz viele Trolle und
machen dir den Thread kaputt. Wenn das Beispiel dir hilft, liegt es
daran, dass ich deine Frage richtig interpretiert habe und nicht weil du
sie gut beschrieben hast.
Ach und wenn jemand mit "Kommt drauf an" antwortet, brauchst du gar
nicht erst weiterlesen. Diese Leute erwarten eine vollständige
Spezifikation bevor sie sich herablassen eine Antwort zu geben. Wenn man
allerdings alles im Detail spezifizieren kann, braucht man eine Antwort
in der Regel auch nicht mehr. Solche Leute werden dann als erstes von
Softwareentwicklern aus Low-Cost Ländern ersetzt. In meinen Augen dann
auch kein Verlust.
Ein guter Ingenieur hat soviel Erfahrung, dass er vor allem fehlerhaft
oder lückenhafte Spezifikationen von sich aus füllen/berichtigen kann
und dann sein Lösungsvorschlag mit dem Auftraggeber zusammen gegen seine
Erwartungen evalutiert.
Mit den Worten zum Donnerstag
ein G4st
PS: Kannst du kurz Feedback geben ob dir das Beispiel geholfen hat?
ausserdem schrieb:> Sorry, ich bin kein fernsehgucker. Musste erst Wikipedia fragen, was 42> bedeutet. Kryptisches mit Kryptischem erklären? Hilft das?
Jeder weiss, was 42 bedeutet. Das gehört zum Grundwissen und wird
typischerweise von den Eltern vermittelt. Es sei denn, die kommen aus
Bielefeld.
42 - die Antwort auf die Frage der Fragen : Was ist der Sinn von Allem.
Siehe : "Hitchhiker guide through the galaxis", oder so
Stellt die ultimaive Antwort auf fast alle Fragen dar.
Die Frage der Fragen wurde dann anders gestellt. Die Frager im Buch
haben dann die Erde gebaut und der Prozess zur Beantwortung laeuft immer
noch.
G4st schrieb:> Ach und wenn jemand mit "Kommt drauf an" antwortet, brauchst du gar> nicht erst weiterlesen. Diese Leute erwarten eine vollständige> Spezifikation bevor sie sich herablassen eine Antwort zu geben. Wenn man> allerdings alles im Detail spezifizieren kann, braucht man eine Antwort> in der Regel auch nicht mehr.
Wenn ich jetzt frage, was ich für mein Auto tanken muss, ist, denke ich,
die Aussage durchaus berechtigt, dass es auf mein Auto ankommt, dass ich
habe. Die Randbedingungen zum Problem zu benennen ist niemals falsch und
ja, oft ergibt sich die Lösung aus den Randbedingungen ganz von alleine.
Der Spruch, dass es hilfreich sei, mal einen Schritt zurück zu machen
und das ganze Bild zu betrachten, kommt nicht von ungefähr ;)
Also ich verstehe das so:
1) Es gibt Daten
2) Daten werden geändert
3) ???
4) Geänderte Daten werden gesendet
Wichtig wäre nun, wann und wohin werden die Daten gesendet? Fragt jemand
nach Änderungen? Oder ist jemand dauerhaft verbunden, und in
regelmässigen Abständen werden die Daten gesendet?
Die Struktur und das Format der Daten ist auch wichtig. Und je nach
Programmiersprache sind unterschiedliche Pattern einfacher umzusetzen.
Zunächst muss herausgefunden werden, ob die Daten geändert wurden. Dann
ist noch die Frage, ob man das erste mal alle Daten braucht, oder ob man
bestimmte Daten Subscriben kann und man nur die dann braucht, oder ob
man die am Anfang manuell holt, etc.
Was sicher nötig ist, wäre eine Datenstruktur, z.B. eine Liste, aller
Objekte, dessen Änderungen gesendet werden sollen. Bei einem subscriber
Modell kann man das pro subscriber machen. Wenn alle alle beobachten
kann man das auch global machen. Oder wenn es sonstige Kriterien je nach
client gibt, kann man das zusammen mit den Infos über den Clienten
speichern.
Je nach Anwendungsfall können auch andere Strukturen sinn machen. z.B.
Bäume bei verschachtelten GUI Elementen, etc.
Ich denke das Erkennen geänderter Daten gibt es 6 wichtige Varianten,
die mir spontan in den Sinn kommen:
1) Es gibt einen callback, der bei jeder Änderung sofort ausgeführt
wird. Man hat dann z.B. immer einen Setter dafür. Oder man verwendet
Transaktionen.
2) Dein Objekt mit den Daten, oder ein wrapper Objekt, hat ein flag, ob
es geändert wurde. Von zeit zu zeit geht man alle einmal durch, sendet
es an alle, und resettet das flag.
3) Jedes Objekt hat ein Hash. Der Client sendet alle seine Hashs, und
der Server sendet alle Objekte, wo dieser nicht mehr übereinstimmt. Kann
je nachdem etwas ineffizient sein, dafür wird so geprüft, dass
tatsächlich eine Änderung vorliegt, und man muss keine sonstigen state
Informationen synchron halten. Das ist super für Caches geeignet, und
wird so bei HTTP E-Tags gemacht. Aber achtung, es kann zu hash
collisions kommen.
4) Jedes Objekt hat einen Änderungstimestamp + einen counter. Bei jeder
Änderung wird ein globaler counter erhöht, und der counter des Objekts
darauf gesetzt, falls der Timestamp unverändert ist. Andernfalls wird
der Timestamp des Objekts gesetzt, und der object counter sowie der
globale counter auf 1 gesetzt. Der Client sendet nach dem
Verbindungsaufbau den höchsten Timestamp + counter den er in seinen
Objekten finden kann. Der server sendet dann alle Objekte, wo
timestamp_client < timestamp_objekt || ( timestamp_client ==
timestamp_objekt && counter_client < counter_objekt ), sortiert so, dass
das kleinste (timestamp, counter) paar zuerst kommt. Man könnte den
Timestamp auch weglassen, und den server counter immer noch irgendwo
persistieren.
5) Bei änderungen wird das Objekt an das ende einer Sendequeue
angehängt. Oder nur dessen serialisierte daten.
6) Ne Kombination der anderen Optionen.
Was ich jetzt oben noch nicht behandle, ist das Löschen von Objekten.
Bei speziellen Formaten, wie z.B. Video Frames, muss man aber komplett
anders vorgehen. Da kann man z.B. Bilder substrahieren, jpeg
kommpressionsartige dinge machen, Translationsmatrizen berechnen, etc.
Und dann kann man das immer noch auf viele weisen Implementieren. Auf
jeden Fall muss man die Daten vor dem Senden noch irgendwie
serialisieren. Idealerweise abstrahiert man dass noch irgendwie. Bei
JavaScript reicht häufig ein JSON.stringify, bzw. in PHP ein
JSON_encode. In C++ gibt es Templatemagie. In C kann man z.B. den Typ
als enum mit speichern, und dann ne lookup Tabelle für
Serialisierungsfunktionen usw. machen. etc. Eventuell nimmt man dafür
auch ein Framework.
Die Prüfung selbst macht man dann da, wo dies am einfachsten und
möglichst einheitlich geht.
Noch was zum Schluss: Versuche immer zusammenhängende Daten
(Verbindungsspezifische Daten eines Clienten, Daten einer Serverinstanz,
etc.) in je eine Datenstruktur zu packen. Sowas in globalen Variablen
unübersichtlich herumschwirren zu haben, kann schnell zum Albtraum
werden.
Fragender schrieb:> Ich wollte mal kurze Frage zum Design des Codens stellen.
"Design des Codens" ... aua!
> Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.
Ähm. Die "Daten die eine Funktion schickt, wenn sie ausgeführt wird",
nennt man üblicherweise Returnwert oder - wenn man zwanghaft
eindeutscht - Rückgabewert. Und der Typ des Rückgabewerts ist fest. Er
ist ein Teil der Funktions→Signatur, ebenso wie der Funktionsname.
> Jetzt möchte ich dazu programmieren, dass die Daten nur geschickt> werden, wenn sie sich auch wirklich geändert haben.
Eine Funktion kann nicht "nichts" zurückgeben. Wenn der Rückgabewert
z.B. vom Typ int ist, dann muß sie einen int zurückgeben. Was du
aber machen kannst: du kannst einen bestimmten Wert, z.B. 0 dahingehend
festlegen, daß er "nichts geändert" bedeutet.
> Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe> ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich> ist.
Man kann eine Funktion nicht "bedingt ausführen". Wenn du außerhalb der
Funktion feststellen kannst, daß sich nichts geändert hat, dann brauchst
du die Funktion natürlich nicht aufzurufen. Aber dann ist deine ganze
Frage sinnlos. Wenn wir hingegen mal annehmen, daß die Entscheidung,
ob sich etwas geändert hat, nur innerhalb der Funktion getroffen
werden kann, daß mußt du die Funktion in jedem Fall aufrufen. Und
brauchst dann natürlich ein if(), um auszuwerten ob die Funktion
vielleicht "es hat sich nichts geändert" zurück gegeben hat. Und
innerhalb der Funktion ein weiteres if(), damit sie das tut.
Im Normalfall wird man diese Prüfung so früh wie möglich machen, damit
man im Fall des Falles möglichst viel Code einsparen kann und die
Sonderbedingung über möglichst wenige Aufrufebenen transportieren muß.
Name H. schrieb:> der Prozess zur Beantwortung laeuft immer> noch.
Nein. Die Erde wurde fünf Minuten vor Ablauf von den Vogonen gesprengt,
um einer Hyperraumumgehungsstraße Platz zu machen.
Axel S. schrieb:>> Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.>> Ähm. Die "Daten die eine Funktion schickt, wenn sie ausgeführt wird",> nennt man üblicherweise Returnwert oder - wenn man zwanghaft> eindeutscht - Rückgabewert. Und der Typ des Rückgabewerts ist fest. Er> ist ein Teil der Funktions→Signatur, ebenso wie der Funktionsname.
Ich denke eher, dass Fragender wirklich eine Funktion meint, die Daten
irgendwo hinsendet. Da kann es durchaus sinnvoll sein, diese nur bei
Änderung neu zu übertragen, wenn die Gegenstelle die Daten speichert.
svensson schrieb:>> Eine Funktion kann nicht "nichts" zurückgeben.> In C kann eine Funktion auch vom Typ "void" sein, dann gibt sie keine> Daten zurück.
Dann gibt sie niemals irgendwas zurück.
Und die Frage des TE erübrigt sich.
Alex D. schrieb:> Axel S. schrieb:>> Die "Daten die eine Funktion schickt, wenn sie ausgeführt wird",>> nennt man üblicherweise Returnwert oder - wenn man zwanghaft>> eindeutscht - Rückgabewert.>> Ich denke eher, dass Fragender wirklich eine Funktion meint, die Daten> irgendwo hinsendet.
Oh. DU meinst im Sinne von: "eine Funktion, die eine Ein-/Ausgabeinheit
(z.B. UART) bedient, um Daten zu verschicken". Hmm, ja. So kann man das
auch interpretieren. Fand ich angesichts der Wortwahl des TE jetzt nicht
naheliegend.
Aber auch dann gilt, was ich schrieb:> Im Normalfall wird man diese Prüfung so früh wie möglich machen, damit> man im Fall des Falles möglichst viel Code einsparen kann und die> Sonderbedingung über möglichst wenige Aufrufebenen transportieren muß.
Thomas E. schrieb:> Die Erde wurde fünf Minuten vor Ablauf von den Vogonen gesprengt,> um einer Hyperraumumgehungsstraße Platz zu machen.
<Trump> So sad! </Trump>
> Dann gibt sie niemals irgendwas zurück.
Muß sie ja auch nicht, da sie Daten versendet.
Dann ist es streng genommen keine Funktion mehr, sondern eine Prozedur.
Axel S. schrieb:> svensson schrieb:>>> Eine Funktion kann nicht "nichts" zurückgeben.>> In C kann eine Funktion auch vom Typ "void" sein, dann gibt sie keine>> Daten zurück.>> Dann gibt sie niemals irgendwas zurück.
Meine Nachbarin ist dann auch eine Funktion. Die gibt auch nie wieder
etwas zurück.
BabyYouCanDriveMyCar schrieb:>> Dann gibt sie niemals irgendwas zurück.>> Meine Nachbarin ist dann auch eine Funktion. Die gibt auch nie wieder> etwas zurück.
Hat deine Nachbarin dann wenigstens Seiteneffekte? Hat sie irgendeine
Wirkung auf Dich? Denn wenn nicht kannst Du sie ersatzlos wegoptimieren!