"Spaghetti"-Code ist die Bezeichnung für Sourcecode der wie eine lange Wurst ist. Alles steht hintereinander, jeder Code kommt mehrmals vor. Schlimm.
Deswegen gibt es Funktionen. Eine Funktion lagert ein bestimmtes verhalten aus. So kann man zB eine Funktion potenzieren() - welche eine bestimmte Zahl hoch einer anderen rechnet und das ergebnis zurückliefert.
Der Sinn liegt auf der Hand: wir müssen nicht jedesmal wenn wir potenzieren wollen eine Schleife schreiben, sondern wir rufen einfach potenzieren() auf. Das hat den Vorteil, dass wir uns nicht immer merken müssen wie potenzieren() implementiert ist. Besteht es aus Additionen, Multiplikationen oder einem ganz coolen Trick? Wir wissen es nicht, und es interessiert uns nicht. Denn wir wissen was es tut, das Wie ist uns egal. Wir können das Wie zu einem späteren Zeitpunkt ändern.
Wenn wir keinen doppelten Code haben, sind auch Korrekturen viel einfacher vorzunehmen. Wenn wir zB einen Fehler in potenzieren() haben, denn x hoch 0 ist bei uns 0 statt 1 - dann müssten wir ja den ganzen Sourcecode durchsuchen und die Schleife überall ausbessern. Wenn wir aber eine Funktion verwenden, müssen wir nur an einem zentralen Punkt diese Änderung vornehmen.
Funktionen bieten eine Möglichkeit Code-Redundanz zu vermeiden - und kaum etwas ist schlimmer als redundanter Code.
Man sollte Funktionen (und auch Methoden (aber die behandeln wir erst später)) möglichst kurz und übersichtlich halten. Als Richtlinie: mehr als 10 Zeilen sind nicht gut, da solltest du dir dann ein anderes Konzept überlgen - aber für den Anfang: verwende Funktionen oft, sollte ab und zu einmal eine Funktion zu lange werden - halb so schlimm.
Viel wichtiger ist, dass eine Funktion exakt 1 Aufgabe zu erledigen haben soll. So sollte Add() nur die 2 Zahlen addieren, nicht aber den User nach diesen 2 Zahlen fragen. 1 Aufgabe pro Funktion.