Zum Inhalt springen

  • Beiträge
    72
  • Kommentare
    239
  • Aufrufe
    12.688

Bachelorarbeit eingereicht


kurtchen

1.084 Aufrufe

Es ist soweit: Am Mittwoch habe ich meine Bachelorarbeit zur Post gebracht. Das war zwei Tage vor dem Abgabetermin. DHL hat die Sache dann noch ein bisschen spannend gemacht. Am nächsten Abend war mein Paket nämlich gerade einmal 10 km weit "gekrochen". Aber am übernächsten Tag kam es doch noch fristgerecht in Dortmund an.

 

Natürlich sind mir schon am Tag nach der Abgabe Fehler aufgefallen, die ich auch beim x-ten Korrekturlesen nicht gesehen hatte. Ebenfalls typisch für mich: Sofort nach der Abgabe ist eine Erkältung ausgebrochen. Die hätte ich mir vorher nicht "gegönnt".

 

Eigentlich hatte ich zur Entstehung der Bachelorarbeit ja mehrere Blogbeiträge schreiben wollen. Aber letztlich musste ich die knapp werdende Zeit in die Bachelorarbeit investieren. Mein Fernstudien-Blog war leider nicht das einzige Hobby, das in den letzten Monaten auf der Strecke blieb.

 

Trotzdem nun ein paar Worte, die wie Sache nun eigentlich gelaufen ist.

 

Inhaltliches

 

Die Grundidee meiner Arbeit war ja ein Vergleich objektorientierter und funktionaler Programmierung an einem Fallbeispiel. Das Fallbeispiel war eine Variante des klassischen Travelling Salesman Problems: In eine Platine sollen von einem Roboter Löcher gebohrt werden. Ein Optimierer solle ein möglichst effiziente Abfolge der Löcher finden. Was genau effizient ist, bestimmt eine Bewertungsfunktion. Hier gab es als einfachste Funktion die euklidische Distanz. Eine Variante nahm an, dass ein Motor des Roboters defekt ist, und daher vertikale Bewegungen nur halb so schnell möglich sind wie horizontale. Eine andere Variante sah vor, dass der Bohrer für einen Bohrerwechsel zurück zum Ursprung kehren muss, falls der Durchmesser aufeinander folgender Löcher sich unterscheidet. Das hatte natürlich große Auswirkungen auf die gefundenen Routen. Die Routen wurden ja auch visualisiert und das war visuell z.T. ganz attraktiv, wie die Anmutung der Routen sich änderte, wenn eine andere Bewertungsfunktion gewählt wurde.

 

Die Routen wurden mit drei verschiedenen Heuristiken optimiert:

  • mit der einfachen und schnellen Nearest-Neighbour-Heuristik
  • mit dem Sintflut-Algorithmus
  • und mit einer Evolutionsstrategie

 

Die beiden letzten Heuristiken ahmen einen Evolutionsprozess nach. Der Sinflut-Algorithmus erzeugt dabei Routenvarianten allein durch Mutation. Außerdem arbeitet er mit einer minimalen Population von nur zwei Individuen: Der bisherigen Lösung und einer neuen Lösung, die akzeptiert oder verworfen wird. Die Evolutionsstrategie simuliert eine größere Population. Sie erzeugt Routenvarianten nicht nur durch Mutation sondern auch durch Rekombination. Sie ahmt also "sexuelle Fortpflanzung" nach. Interessant war dann z.B. die Frage, was geeignete Mutations- und Rekombinationsoperatoren für ein Travelling Salesman Problem sind.

 

Die beiden Heuristiken unterscheiden sich auch beim Selektionsmechanismus. Sintflut arbeitet mit der Metapher eines steigenden Wasserspiegels. Eine Routenvariante wird akzeptiert, solange ihre "Fitness" nur besser als der momentane Wasserspiegel ist. Auch dann, wenn sie gegenüber der letzten Routenvariante schlechter ist. Das ist entscheidend, damit der Algorithmus ein lokales Optimum überwinden kann. Mit steigendem Wasserspiegel wird die Selektion immer härter, so dass gegen Ende der Optimierung nur noch Verbesserungen akzeptiert werden. Sintflut geht also nach und nach in einen sogenannten Bergsteiger-Algorithmus über. Meine Fallstudie arbeitete mit einer variablen Regenrate. Wenn die Optimierung stagnierte, regnete es gar nicht. Wenn sie voran schritt, regnete es umso stärker, je größer die Differenz zwischen momentaner Fitness und Wasserspiegel war.

 

Bei der Evolutionsstrategie wurde die Selektion durch den Wettbewerb innerhalb eine Population bestimmt. Meine Implementierung arbeitete mit einer (µ+λ)-Selektion. Dabei steht µ für die Elterngeneration und λ für die durch Rekombination von Genen und Mutation entstandenen Kinder. Die Kinder geraten also in Wettbewerb mit der Generation ihrer Eltern. Theoretisch könnte man dieser Form der Selektion ein Individuum beliebig viele Generationen überlegen, wenn seine Fitness nur hoch genug ist. Es gibt viele mögliche Selektionsoperatoren. Individuen mit hoher Fitness haben eine höhere Chance, die Selektion zu überleben, aber wie bei der natürlichen Selektion spielt i.d.R. auch der Zufall eine Rolle.

 

Am besten funktionierte der noch vergleichsweise einfache Sintflut-Algorithmus. Die Evolutionsstrategie war nicht nur langsamer sondern brachte auch etwas schlechtere Ergebnisse. Ich vermute, dass lag am früh einsetzenden Selektionsdruck durch Wettbewerb innerhalb der Population. Der führte dazu, dass die Optimierung früher als bei Sintflut in einem lokalen Optimum hängenblieb. Es wäre spannend gewesen, mehr mit den Selektionskriterien zu spielen, um zu schauen, ob man Sinflut so nicht doch einholen kann. Auch weiß ich inzwischen, dass es bessere Rekombinationsoperatoren gegeben hätte. Leider fehlte mir die Zeit, diese noch zu implementieren und auszuprobieren. Aber es war schon faszinierend anzusehen, wie das Duo aus Mutation und Selektion eine Route optimiert. Die Software hatte ein einfaches GUI, das periodisch Momentaufnahmen der laufenden Optimierung zeigte. Der Moment, in dem es erstmals klappte, und man zuschauen konnte, wie die Routenlängen fielen, war schon sehr befriedigend.

 

Allerdings war heuristische Optimierung ja nur das Fallbeispiel für einen Vergleich der Programmierparadigmen. Darum habe ich die gleichen Heuristiken in Java, Scala und Clojure implementiert.

 

Meine persönliche Motivation für dieses Thema war, dass ich eine empfundene fachliche Lücke meines Studiums schließen wollte. Ich wollte funktionale Programmierung und funktionale Programmiersprachen besser kennenlernen, als das im Curriculum meines Studiums vorgesehen war. Dieser Wunsch ging für mich in Erfüllung. Bei der Implementierung der Optimierer in Scala und Clojure konnte ich viele Aspekte funktionaler Programmierung erleben und anwenden: Funktionen höherer Ordnung, (End-)Rekursion, Verwendung persistenter Datenstrukturen, Closures, partielle Funktionen, Lazy Evaluation und Lazy Sequences und einiges mehr. Wie erwartet, war es so in vielen Fällen möglich, kompakteren und dennoch gut lesbaren Code zu schreiben. Vor allem war der funktionale Code oft deklarativer als der imperative. Er war also eher eine Beschreibung der Problemlösung als eine kleinschrittige Handlungsanweisung für den Computer. Im Vergleich zur objektorientierten Programmierung war es schon faszinierend, sich als Programmierer so gegenüber der Maschine ausdrücken zu können.

 

Leider hatte insbesondere die Verwendung persistenter Datenstrukturen ihren Preis. Die in Scala implementierten Optimierer liefen deutlich langsamer als ihre Gegenstücke in Java. Die Performance ließ sich verbessern, indem man (zumindest vorrübergehend) doch veränderliche Datenstrukturen verwendete. Leider fiel der Code dann nicht mehr so elegant und deklarativ aus. Er ähnelte wieder stärker den imperativen Lösungen. Auf einem höheren Abstraktionsniveau mit dem Computer zu kommunizieren hat also einen Preis.

 

Obwohl Scala Java syntaktisch viel ähnlicher ist als Clojure, dauerte es länger, eine Heuristik von Java nach Scala zu portieren. Die Portierung von Scala nach Clojure war dagegen meist sehr schnell erledigt, obwohl die lispoide Syntax für mich anfangs sehr fremdartig war. An dieser Stelle war spürbar, was es heißt, sich innerhalb eines Programmierparadigmas oder eben zwischen verschiedenen Programmierparadigmen zu bewegen. Bleibt man innerhalb eines Paradigmas, hat man das Gefühl, alle Sprachen sind gleich. Wechselt man zwischen den Paradigmen, merkt man, dass jede Sprache ihr Paket an impliziten Denkweisen und Lösungsstrategien mit sich trägt.

 

Clojure war als dynamisch typisierte Sprache natürlich noch einmal deutlich langsamer als Scala. Bei Clojure bedauere ich, dass die Zeit nicht reichte, um Metaprogrammierung mit Makros auszuprobieren.

 

Scala gefällt mir als Programmiersprache gut. Ich finde es z.B. toll, dass man es einerseits als funktionale aber andererseits auch als objektorientierte Sprache verwenden kann. Auch wenn man objektorientiert programmiert, erlaubt es an vielen Stellen kompakteren und zugleich besser lesbareren Code als Java. Ich glaube, es gibt in meiner Region sogar ein Softwareunternehmen, das diese Sprache produktiv einsetzt. Inzwischen wäre ich auch neugierig, mit Kotlin eine weitere multi-paradigmatische Sprache auf der JVM kennenzulernen.

 

Betreuung

 

Meinen Erstbetreuer kannte ich schon von der Projektarbeit. Er bekam fortlaufend Textbausteine geschickt. Wie in Aussicht gestellt, kamen anfangs mehr Rückmeldungen und mit fortschreitender Arbeit wurde es knapper. Das fand ich genau richtig. Ich habe mich gut begleitet gefühlt, hatte aber auch den Eindruck, selbst für meine Bachelorarbeit zuständig zu sein. Toll war für mich, dass mir das Studienbüro einen Betreuer vermitteln konnte, der für mein Wunschthema offen war.

 

Ich bin ein bisschen gespannt, was mein Zweitbetreuer zu meiner Arbeit sagen wird. Er bekam sie erst am Schluss, als sie fertig war, so dass ich ihn noch nicht richtig kennenlernen konnte. Aber beim Kolloquium muss ich mich ja den Fragen beider Betreuer stellen.

 

Mal schauen, wie lange es nun dauert, bis eine Rückmeldung kommt. Ich werde im Blog berichten.

 

Tools und Werkzeuge

 

Lohnend war in jedem Fall, dass ich mir schon letztes Jahr die Mühe gemacht hatte, eine brauchbare LaTeX-Vorlage zu erstellen. Für eine Arbeit mit vielen Abbildungen, Fußnoten, Querverweisen, Verzeichnissen und Quellenangaben ist es sehr angenehm, sich Dank LaTeX aufs Schreiben konzentrieren zu können und sich nicht mit dem Layout herumschlagen zu müssen.

 

Meine Quellen habe ich als einfache Textdatei mit einem Texteditor erfasst. Ich war anfangs der Ansicht, für eine Bachelorarbeit würden es ja wohl nicht so viele Quellen werden, so dass eine Literaturverwaltung mir übertrieben vorkam. Am Ende wurden es doch mehr Quellen als ich gedacht hätte. Stünde ich noch einmal am Anfang, würde ich eine Literaturverwaltung verwenden.

 

Als IDE habe ich IntelliJ verwendet. Die hat eine gute Unterstützung für Scala. Man kann sie auch für Clojure verwenden. Allerdings hat es sich als etwas schwierig erwiesen, Scala und Clojure im gleichen Projekt zu verwenden. (Dazu nur ein Beispiel: Scala-Projekte nutzen als Build Tool bevorzugt das SBT. Clojure-Projekte verwenden meist Leinigen. Prinzipiell müsste es möglich sein, mit dem SBT auch Clojure oder mit Leiningen auch Scala zu compilieren, aber ein entsprechendes Setup habe ich nicht hinbekommen.)

 

Für die Erstellung von UML-Diagrammen habe ich UMLet verwendet. Es ist ein bisschen "spartanisch", aber dafür ist es auch schlank und erschlägt einen nicht mit der Vielfalt seiner Features.

 

Zeitmanagement

 

Im Großen und Ganzen hat meine Zeiteinteilung funktioniert. Inzwischen bin ich alt genug, um begriffen zu haben, dass ein noch so guter Plan nie hinhaut und man daher stets Puffer für Unerwartetes einplanen muss.

 

Die hätten allerdings noch ein bisschen üppiger ausfallen dürfen. Insgesamt habe ich mir doch mehr vorgenommen, als im Rahmen einer Bachelorarbeit realistisch war. So musste ich gegen Ende auf ein paar Themen und Aspekte verzichten, die ich gerne noch erkundet hätte. Zum Beispiel bietet Scala nebenläufige Programmierung auf einem höheren Abstraktionsniveau mit Aktoren. Die hätte ich gerne für die Evolutionsstrategie verwendet, aber dafür reichte die Zeit nicht mehr.

 

Es wäre auch gut gewesen, am Ende mehr Zeit für Korrekturen zu haben. Eigentlich hatte ich dafür eine ganze Woche eingeplant, aber dann musste es doch schneller gehen. Zwar hatte ich zwischendurch immer wieder Kapitel gelesen und überarbeitet, aber ich war doch jedes Mal wieder erstaunt, dass man auch nach dem x-ten Durchgang wieder etwas findet.

Das Drucken und Binden war diesmal stressfrei, weil ich schon eine ganze Weile vorher im Copyshop vorstellig geworden war und vorgefühlt hatte, wie ausgelastet die Mitarbeiter waren. So konnte ich eine klare Vereinbarung treffen und das lief dann auch genau so.

 

Ausblick

 

Nun heißt es, loslassen und abwarten, was meine Betreuer sagen. Somit habe ich, eigentlich zum ersten Mal seit Beginn meines Studium, so etwas wie "Leerlauf". Das kann ich inzwischen aber auch gut gebrachen. In den letzten Monaten ist einiges auf der Strecke geblieben; Hobbies zum Beispiel. Gestern habe ich zum ersten Mal wieder ein bisschen Klavier geübt. Das möchte ich nun wieder regelmäßiger machen.

 

Ich hoffe ein bisschen, dass es noch vor Jahresende zum Kolloquium kommt. Wäre schön, wenn ich das Studium mit dem alten Jahr abschließen könnte.

 

Auch aus einem praktischen Grund wäre das gut. Der Kindergarten, in dem ich während meines gesamten Studiums gearbeitet habe, kann mich ab Januar nicht mehr beschäftigen. Es sind Zuschüsse weggefallen, die für die Finanzierung meiner Stelle wesentlich waren. Darum stehen zwingend berufliche Veränderungen an.

 

Meine Idee bei Aufnahme des Studiums war ja, einen Branchenwechsel hinzulegen: Von der Frühpädagogik zur IT. Das Problem dürfte dabei mein Alter werden. Man liest zwar beinahe täglich in der Zeitung, dass Informatiker gesucht werden. Aber bald werde ich erleben, ob das auch gilt, wenn sie Berufseinsteiger im mittleren Alter sind.

 

Sorgen muss ich mir eigentlich nicht machen, denn in meiner Region kann man als Kindergärtner kaum arbeitslos werden. In den letzten Wochen habe ich neue Kinder eingewöhnt und wieder einmal gemerkt, wie identitätsstiftend diese Arbeit in der ersten Hälfte meines Berufslebens für mich war. Eigentlich bin ich immer noch stolz, dass ich mich als junger Erwachsener für diesen Beruf entschieden habe; zu einer Zeit, als es noch absolut unüblich war, dass Männer in Kindergärten arbeiteten. Insofern mache ich mich nicht verrückt. Falls die Arbeitgeber mir nicht zutrauen, in meinem Alter noch ein guter Informatiker zu werden, bleibe ich eben Kindergärtner. Das kann ich immer noch ganz gut.

 

Wenn die Bachelorarbeit bestanden ist, bleibt als letzter Baustein des Studiums tatsächlich nur noch das Kolloquium. Darüber mache ich mir im Moment aber noch keine Gedanken. Aktuell versuche ich, nach den intensiven letzten Monaten ein bisschen Abstand zu meiner Bachelorarbeit zu gewinnen.

 

Für diesen Blog heißt das, dass es wohl nicht mehr allzu viele Beiträge werden. Ich möchte noch über das Kolloquium berichten. Und danach noch einmal rückblickend, den Studiengang als Ganzes betrachten. Aber möglicherweise besuche ich vorher noch einmal einen Präsenztag in Dortmund, so dass es vielleicht auch noch drei Beiträge werden könnten.

 

Bildergalerie

 

optimierer-total.thumb.png.1e24ffd7830d3bd9f3f6d19cb1ea8b8c.png

 

Das erste Bild zeigt den implementierten Optimierer vor einem Lauf. Geladen ist das sogenannte 442-Problem, eine Platine mit 442 Bohrlöchern, die im Zusammenhang mit dem TSP gerne als Testfall benutzt wird. Die Koordinaten der Löcher wurden mir freundlicherweise von Dr. Johannes Josef Schneider von der ZHAW Winterthur zur Verfügung gestellt. Das Bild zeigt eine zufällig generierte - also noch nicht optimierte - Route. Das schöne am 442-Problem ist, dass dafür eine optimale Lösung bestimmt werden konnte. Gelbe Kanten zeigen an, dass aufeinander folgende Löcher den gleichen Durchmesser haben. Hellrote Kanten zeigen dagegen, dass die Lochdurchmesser sich unterscheiden, was einen Bohrerwechsel nötig macht. (Das originale 442-Problem kennt keine Lochdurchmesser. Das ist eine Variation, die ich eingebaut habe, weil ich mit verschiedenen Bewertungsfunktionen experimentieren wollte.)

 

holes-442.png.dfe601543cd744de1c5bb0e21743a56d.png

 

Das zweite Bild zeigt die Anordnung der Löcher des 442-Problems. Eine optimale Lösung konnte im Jahr 1987 gefunden werden, weil viele Löcher in horizontalen oder vertikalen Linien angeordnet sind. Dies ließ sich mathematisch verwerten, um viele mögliche Routen auszuschließen. Wie genau das funktioniert, verstehe ich freilich nicht; ich bin leider nur Informatiker, kein Mathematiker. Relevant für mich war, dass eine optimale Rundreise nachweislich eine Länge von ca. 5078 mm hat. Das liefert einen Anhaltspunkt dafür, wie gut die Optimierung - z.B. mit dem Sintflut-Algorithmus -  funktioniert.

 

run-si.png.5e28415d2ddc41f8a7f79c3b5f859dde.png

 

Das dritte Bild zeigt eine mit dem Sintflut-Algorithmus optimierte Tour. Hier wurde die Route in ca. 8 Sekunden auf 5321 mm verkürzt. Sie ist somit lediglich 4,7% länger als die optimale Route. Lässt man es langsamer regnen, so braucht die Optimierung etwas länger, aber der Algorithmus findet kürzere Routen, die nur noch ca. 2,5% länger sind als die optimale Route.

4 Kommentare


Empfohlene Kommentare

Sehr spannend, auch wenn ich nicht annähernd die Hälfte verstehe. Deine Begeisterung für das Thema merkt man deinem Blogeintrag richtig an. Auch die Reflexion ist sehr ausführlich. So kann das Kolloquium nur gut werden, dafür wünsche ich dir viel Erfolg! 

 

Mit dem Branchenwechsel würde ich mir auch keinen Kopf machen, aus eigener Erfahrung weiß ich, dass das Alter und die Geradlinigkeit des Lebenslaufs nicht mehr furchtbar relevant sind. Für eventuelle Wartezeiten bist du ja auch bestens gerüstet. 

Link zu diesem Kommentar

Hier einmal ein Codebeispiel in der funktionalen Sprache Clojure. Es ist die Definition einer Funktion by-sample, die für den Sintflut-Algorithmus einen anfänglichen Wasserspiegel bestimmt. Dieser sollte so gewählt werden, dass zu Beginn der Optimierung jede noch so schlechte Routenvariante akzeptiert wird. Es gibt verschiedene Möglichkeiten, dies zu tun. Eine vergleichsweise einfache Möglichkeit ist, eine überschaubare Anzahl zufälliger Routen zu erzeugen, deren durchschnittliche Länge zu bestimmen und diese mit einem Korrekturfaktor zu multiplizieren.

Zitat

(defn by-sample [route dist-function]
  (as-> (repeatedly #(shuffle-route route)) x
        (take sample-size x)
        (map  #(length-route %1 dist-function) x)
        (reduce + x)
        (/ x sample-size)
        (* x factor-sample)))

 

  • Die Funktion erhält in Zeile 1 als Parameter eine Rundreise und eine Funktion zur Bewertung des Abstandes zwischen zwei Bohrlöchern. Die Funktion by-sample ist eine Funktion höherer Ordnung, weil ihr eine Funktion als Parameter übergeben wird. Die folgenden Zeilen zeigen die in der funktionalen Programmierung häufig auftretende Verkettung von Funktionen. So etwas nennt man auch Chain of Operations.
  • In Zeile 2 wird mittels der Funktion repeatedly eine prinzipiell unendliche Sequenz zufälliger Routenvarianten erzeugt. Die Funktion arbeitet mit lazy evaluation, d.h. sie tut zunächst einmal gar nichts. Es genügt, dass prinzipiell bekannt ist, wie Routenvarianten erzeugt werden.
  • In Zeile 3 werden der unendlichen Sequenz ein paar Elemente als Stichprobe entnommen. Das macht die Funktion take. Die Konstante sample-size gibt an, wie groß die Stichprobe ist. Erst im Moment der Entnahme, werden von repeatedly tatsächlich Routenvarianten erzeugt. Und auch nur genau so viele, wie in diesem Moment benötigt werden. Man erhält so eine Liste einer bestimmten Länge mit zufälligen Routenvarianten.
  • In Zeile 4 wird mittels der Funktion höherer Ordnung map eine Bewertungsfunktion auf jede Route der Liste angewendet. Man erhält so eine neue Liste der Routenlängen. Die ursprüngliche Liste der Routenvarianten bleibt davon unberührt.
  • In Zeile 5 wird die Liste der Routenlängen mit der Funktion höherer Ordnung reduce auf einen einzelnen Wert reduziert. Ihr wird dazu die Funktion + übergeben. Die Elemente der Liste werden somit aufaddiert zur Summe der Routenlängen.
  • In Zeile 6 wird diese Summe durch die Größe der Stichprobe geteilt und somit die durchschnittliche Routenlänge bestimmt. In Zeile 7 wird diese durchschnittliche Routenlänge mit einem Korrekturfaktor multipliziert und somit der anfängliche Wasserspiegel festgelegt. Wie in der funktionalen Programmierung üblich, wird das Ergebnis dieses letzten Ausdrucks implizit als Ergebnis der Funktion zurückgegeben.

 

In Zeile 2 steht das Threading Macro as->. Er reicht das Ergebnis jeder Zeile als Wert x an die jeweils nächste Zeile weiter. Auf diese Weise entsteht eine Art Verarbeitungs-Pipeline aus Funktionsaufrufen, die sogenannte Chain of Operations.

 

Clojure ist ein LISP-Dialekt. Lispoide Sprache haben eine eigenwillige Syntax mit ineinander geschachtelten Funktionsaufrufen. Das führt dazu, dass der Code oft viele Klammern und Klammerebenen enthält. Hier fällt das dank des Threading Macros as-> sogar noch recht moderat aus. Wer LISP nicht mag, stört sich oft an den Klammern.

 

Allerdings hat LISP der Vorzug, ein einfaches syntaktisches Prinzip stur und ohne Ausnahmen durchzuziehen. Ein LISP-Ausdruck ist eine Liste, deren Elemente durch eine Klammer eingeschlossen sind. Das erste Listenelement ist eine Funktion. Die restlichen Listenelemente sind die Argumente, die die Funktion verarbeitet. Listen sind die grundlegende Datenstruktur in LISP. Zugleich ist jedes LISP-Programm eine Liste, also eine Datenstruktur, die durch LISP erzeugt oder verarbeitet werden kann. Dieses Sprachmerkmal nennt man auch Homoikonizität. Man umschreibt dies auch mit dem Schlagwort: "Code is data, data is code." Es ist daher in LISP vergleichsweise einfach, Programme zu schreiben, die LISP-Code verarbeiten oder LISP-Code erzeugen. Dies bezeichnet man als Metaprogrammierung.

Link zu diesem Kommentar

Hey, das ist richtig super, klasse.

 

Vor allem das erste Bid finde ich irgendwie faszinierend. Stelle das in eine Gallerie und verlange ein paar T€ dafür 😄

Ja, diese Leere nach der Abgabe der Bachelorarbeit ist schon komisch. Ich hatte in der ersten Woche nach der Abgabe sooo viele Dinge tun wollen. Ich begann, Filme zu schauen, die ich seit Ewigkeiten sehen wollte, Bücher zu lesen, die schon Staub angesetzt hatten, mit Freunden raus zu gehen, die sich wunderten, dass ich nach Jahren auf einmal so spontan Zeit hatte.

Aber dennoch würde ich mir so langsam an der pptx. und dem freien Sprechen üben. Richtig gut getan hatte es mir, auf der Arbeit vor ein paar Kollegen zu sprechen. Die geben noch gutes Feedback. Ich weiß allerdings nicht, inwieweit dir die Kita bei dem Thema helfen kann... :)

Link zu diesem Kommentar

Von außen betrachtet bin ich erstaunt, wie schnell das jetzt am Ende doch plötzlich ging. Gefühlt hast du für mich gerade erst mit der Bachelor-Thesis begonnen 😉.

 

So tief, wie du dich hier in die Materie eingearbeitet hast schätze ich deine Chancen für einen Berufswechsel recht gut ein - wobei es natürlich sehr hilfreich ist, dass du mit der Kita ein Sicherheitsnetz hast, auf das du zurückgreifen kannst.

 

 

Link zu diesem Kommentar

Erstelle ein Benutzerkonto oder melde Dich an, um zu kommentieren

Du musst ein Benutzerkonto haben, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen. Es ist einfach!

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde Dich hier an.

Jetzt anmelden


×
  • Neu erstellen...