To further add to what I said:
In early versions of BASIC there was no variable scope. All variables were global. Line numbers were required (10, 20, 30, 40, etc.) and GOSUB jumped to a line number. QBASIC got rid of the requirement for line numbers, and added optional line labels (labels behave like line numbers, in global scope, but have an easier to remember name rather than a number). I can still remember the first time I used QBASIC after years of Commodore 64 BASIC and DOS GW-BASIC, it was so weird not needing line numbers! I could barely believe it. And an IDE that showed you your whole program! In GW-BASIC you were left going LIST to display your lines of code, and if it was more than a screen of lines, you'd be forced to work out a range to display, like LIST 150-180.
20 INPUT "Enter number 1: ", Num1!
30 INPUT "Enter number 2: ", Num2!
30 PRINT Num1!;
"+"; Num2!;
"=";
(Num1!
+ Num2!
)
People usually went by 10s for line numbers, that way you could add up to 9 more lines in-between existing lines without being forced to renumber existing lines to make room. For example, in the above addition app, if I wanted to print a blank line after the answer, I could do that as:
QBASIC with no line number requirements was a breath of fresh air! It made coding
MUCH simpler and easier, especially when making changes then testing, changes then testing... in GW-BASIC you had to go by 100s if you wanted to make sure you would have enough space to add groups of lines later, or else forced to use GOTO spaghetti code to jump around, which was an absolute nightmare for code readibility!
GOSUB came from that time period. It was better than GOTO, because you returned to where you started after, but it was still confusing keeping track of all the subroutines splashed around the code. I would often add huge line numbers for my subs so they stayed at the bottom, such as starting my subs at line 8000.
SUB + END SUB was an amazing game changer when it came out. No strict line numbers, neatly grouped together at the end of your code, accessible within the IDE with F2 including pressing F2 on a subroutine's name, new FUNCTION ability with a data type (e.g. MyStringFunc$ returns a string).
The only time to use GOSUB in a modern BASIC would be quick-and-dirty proof-of-concept programming. Hacking something together where the only goal is getting it done fast. For the most manageable code that is easiest to read and quick to update, definitely stick to SUB + END SUB / FUNCTION + END FUNCTION. In my opinion.