¿Por qué main () debe ser corto?

87

He estado programando durante más de 9 años, y de acuerdo con el consejo de mi primer maestro de programación, siempre mantengo mi main()función extremadamente corta.

Al principio no tenía idea de por qué. Simplemente obedecí sin entender, para deleite de mis profesores.

Después de ganar experiencia, me di cuenta de que si diseñaba mi código correctamente, main()simplemente tenía una función corta . Escribir código modular y siguiendo el principio de la responsabilidad individual permitió que mi código que se ha diseñado en "racimos", y main()sirvió como nada más que un catalizador para obtener el programa en ejecución.

Un avance rápido hasta hace unas semanas, estaba mirando el código fuente de Python, y encontré la main()función:

/* Minimal main program -- everything is loaded from the library */

...

int
main(int argc, char **argv)
{
    ...
    return Py_Main(argc, argv);
}

Yay pitón. main()Función corta == Buen código.

Los maestros de programación tenían razón.

Queriendo mirar más profundo, eché un vistazo a Py_Main. En su totalidad, se define de la siguiente manera:

/* Main program */

int
Py_Main(int argc, char **argv)
{
    int c;
    int sts;
    char *command = NULL;
    char *filename = NULL;
    char *module = NULL;
    FILE *fp = stdin;
    char *p;
    int unbuffered = 0;
    int skipfirstline = 0;
    int stdin_is_interactive = 0;
    int help = 0;
    int version = 0;
    int saw_unbuffered_flag = 0;
    PyCompilerFlags cf;

    cf.cf_flags = 0;

    orig_argc = argc;           /* For Py_GetArgcArgv() */
    orig_argv = argv;

#ifdef RISCOS
    Py_RISCOSWimpFlag = 0;
#endif

    PySys_ResetWarnOptions();

    while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
        if (c == 'c') {
            /* -c is the last option; following arguments
               that look like options are left for the
               command to interpret. */
            command = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (command == NULL)
                Py_FatalError(
                   "not enough memory to copy -c argument");
            strcpy(command, _PyOS_optarg);
            strcat(command, "\n");
            break;
        }

        if (c == 'm') {
            /* -m is the last option; following arguments
               that look like options are left for the
               module to interpret. */
            module = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (module == NULL)
                Py_FatalError(
                   "not enough memory to copy -m argument");
            strcpy(module, _PyOS_optarg);
            break;
        }

        switch (c) {
        case 'b':
            Py_BytesWarningFlag++;
            break;

        case 'd':
            Py_DebugFlag++;
            break;

        case '3':
            Py_Py3kWarningFlag++;
            if (!Py_DivisionWarningFlag)
                Py_DivisionWarningFlag = 1;
            break;

        case 'Q':
            if (strcmp(_PyOS_optarg, "old") == 0) {
                Py_DivisionWarningFlag = 0;
                break;
            }
            if (strcmp(_PyOS_optarg, "warn") == 0) {
                Py_DivisionWarningFlag = 1;
                break;
            }
            if (strcmp(_PyOS_optarg, "warnall") == 0) {
                Py_DivisionWarningFlag = 2;
                break;
            }
            if (strcmp(_PyOS_optarg, "new") == 0) {
                /* This only affects __main__ */
                cf.cf_flags |= CO_FUTURE_DIVISION;
                /* And this tells the eval loop to treat
                   BINARY_DIVIDE as BINARY_TRUE_DIVIDE */
                _Py_QnewFlag = 1;
                break;
            }
            fprintf(stderr,
                "-Q option should be `-Qold', "
                "`-Qwarn', `-Qwarnall', or `-Qnew' only\n");
            return usage(2, argv[0]);
            /* NOTREACHED */

        case 'i':
            Py_InspectFlag++;
            Py_InteractiveFlag++;
            break;

        /* case 'J': reserved for Jython */

        case 'O':
            Py_OptimizeFlag++;
            break;

        case 'B':
            Py_DontWriteBytecodeFlag++;
            break;

        case 's':
            Py_NoUserSiteDirectory++;
            break;

        case 'S':
            Py_NoSiteFlag++;
            break;

        case 'E':
            Py_IgnoreEnvironmentFlag++;
            break;

        case 't':
            Py_TabcheckFlag++;
            break;

        case 'u':
            unbuffered++;
            saw_unbuffered_flag = 1;
            break;

        case 'v':
            Py_VerboseFlag++;
            break;

#ifdef RISCOS
        case 'w':
            Py_RISCOSWimpFlag = 1;
            break;
#endif

        case 'x':
            skipfirstline = 1;
            break;

        /* case 'X': reserved for implementation-specific arguments */

        case 'U':
            Py_UnicodeFlag++;
            break;
        case 'h':
        case '?':
            help++;
            break;
        case 'V':
            version++;
            break;

        case 'W':
            PySys_AddWarnOption(_PyOS_optarg);
            break;

        /* This space reserved for other options */

        default:
            return usage(2, argv[0]);
            /*NOTREACHED*/

        }
    }

    if (help)
        return usage(0, argv[0]);

    if (version) {
        fprintf(stderr, "Python %s\n", PY_VERSION);
        return 0;
    }

    if (Py_Py3kWarningFlag && !Py_TabcheckFlag)
        /* -3 implies -t (but not -tt) */
        Py_TabcheckFlag = 1;

    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
        Py_InspectFlag = 1;
    if (!saw_unbuffered_flag &&
        (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
        unbuffered = 1;

    if (!Py_NoUserSiteDirectory &&
        (p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0')
        Py_NoUserSiteDirectory = 1;

    if ((p = Py_GETENV("PYTHONWARNINGS")) && *p != '\0') {
        char *buf, *warning;

        buf = (char *)malloc(strlen(p) + 1);
        if (buf == NULL)
            Py_FatalError(
               "not enough memory to copy PYTHONWARNINGS");
        strcpy(buf, p);
        for (warning = strtok(buf, ",");
             warning != NULL;
             warning = strtok(NULL, ","))
            PySys_AddWarnOption(warning);
        free(buf);
    }

    if (command == NULL && module == NULL && _PyOS_optind < argc &&
        strcmp(argv[_PyOS_optind], "-") != 0)
    {
#ifdef __VMS
        filename = decc$translate_vms(argv[_PyOS_optind]);
        if (filename == (char *)0 || filename == (char *)-1)
            filename = argv[_PyOS_optind];

#else
        filename = argv[_PyOS_optind];
#endif
    }

    stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0);

    if (unbuffered) {
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
        _setmode(fileno(stdin), O_BINARY);
        _setmode(fileno(stdout), O_BINARY);
#endif
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
#else /* !HAVE_SETVBUF */
        setbuf(stdin,  (char *)NULL);
        setbuf(stdout, (char *)NULL);
        setbuf(stderr, (char *)NULL);
#endif /* !HAVE_SETVBUF */
    }
    else if (Py_InteractiveFlag) {
#ifdef MS_WINDOWS
        /* Doesn't have to have line-buffered -- use unbuffered */
        /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
#else /* !MS_WINDOWS */
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IOLBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
#endif /* HAVE_SETVBUF */
#endif /* !MS_WINDOWS */
        /* Leave stderr alone - it should be unbuffered anyway. */
    }
#ifdef __VMS
    else {
        setvbuf (stdout, (char *)NULL, _IOLBF, BUFSIZ);
    }
#endif /* __VMS */

#ifdef __APPLE__
    /* On MacOS X, when the Python interpreter is embedded in an
       application bundle, it gets executed by a bootstrapping script
       that does os.execve() with an argv[0] that's different from the
       actual Python executable. This is needed to keep the Finder happy,
       or rather, to work around Apple's overly strict requirements of
       the process name. However, we still need a usable sys.executable,
       so the actual executable path is passed in an environment variable.
       See Lib/plat-mac/bundlebuiler.py for details about the bootstrap
       script. */
    if ((p = Py_GETENV("PYTHONEXECUTABLE")) && *p != '\0')
        Py_SetProgramName(p);
    else
        Py_SetProgramName(argv[0]);
#else
    Py_SetProgramName(argv[0]);
#endif
    Py_Initialize();

    if (Py_VerboseFlag ||
        (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) {
        fprintf(stderr, "Python %s on %s\n",
            Py_GetVersion(), Py_GetPlatform());
        if (!Py_NoSiteFlag)
            fprintf(stderr, "%s\n", COPYRIGHT);
    }

    if (command != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    if (module != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c'
           so that PySys_SetArgv correctly sets sys.path[0] to ''
           rather than looking for a file called "-m". See
           tracker issue #8202 for details. */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);

    if ((Py_InspectFlag || (command == NULL && filename == NULL && module == NULL)) &&
        isatty(fileno(stdin))) {
        PyObject *v;
        v = PyImport_ImportModule("readline");
        if (v == NULL)
            PyErr_Clear();
        else
            Py_DECREF(v);
    }

    if (command) {
        sts = PyRun_SimpleStringFlags(command, &cf) != 0;
        free(command);
    } else if (module) {
        sts = RunModule(module, 1);
        free(module);
    }
    else {

        if (filename == NULL && stdin_is_interactive) {
            Py_InspectFlag = 0; /* do exit on SystemExit */
            RunStartupFile(&cf);
        }
        /* XXX */

        sts = -1;               /* keep track of whether we've already run __main__ */

        if (filename != NULL) {
            sts = RunMainFromImporter(filename);
        }

        if (sts==-1 && filename!=NULL) {
            if ((fp = fopen(filename, "r")) == NULL) {
                fprintf(stderr, "%s: can't open file '%s': [Errno %d] %s\n",
                    argv[0], filename, errno, strerror(errno));

                return 2;
            }
            else if (skipfirstline) {
                int ch;
                /* Push back first newline so line numbers
                   remain the same */
                while ((ch = getc(fp)) != EOF) {
                    if (ch == '\n') {
                        (void)ungetc(ch, fp);
                        break;
                    }
                }
            }
            {
                /* XXX: does this work on Win/Win64? (see posix_fstat) */
                struct stat sb;
                if (fstat(fileno(fp), &sb) == 0 &&
                    S_ISDIR(sb.st_mode)) {
                    fprintf(stderr, "%s: '%s' is a directory, cannot continue\n", argv[0], filename);
                    fclose(fp);
                    return 1;
                }
            }
        }

        if (sts==-1) {
            /* call pending calls like signal handlers (SIGINT) */
            if (Py_MakePendingCalls() == -1) {
                PyErr_Print();
                sts = 1;
            } else {
                sts = PyRun_AnyFileExFlags(
                    fp,
                    filename == NULL ? "<stdin>" : filename,
                    filename != NULL, &cf) != 0;
            }
        }

    }

    /* Check this environment variable at the end, to give programs the
     * opportunity to set it from Python.
     */
    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
    {
        Py_InspectFlag = 1;
    }

    if (Py_InspectFlag && stdin_is_interactive &&
        (filename != NULL || command != NULL || module != NULL)) {
        Py_InspectFlag = 0;
        /* XXX */
        sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0;
    }

    Py_Finalize();
#ifdef RISCOS
    if (Py_RISCOSWimpFlag)
        fprintf(stderr, "\x0cq\x0c"); /* make frontend quit */
#endif

#ifdef __INSURE__
    /* Insure++ is a memory analysis tool that aids in discovering
     * memory leaks and other memory problems.  On Python exit, the
     * interned string dictionary is flagged as being in use at exit
     * (which it is).  Under normal circumstances, this is fine because
     * the memory will be automatically reclaimed by the system.  Under
     * memory debugging, it's a huge source of useless noise, so we
     * trade off slower shutdown for less distraction in the memory
     * reports.  -baw
     */
    _Py_ReleaseInternedStrings();
#endif /* __INSURE__ */

    return sts;
}

Buen Dios Todopoderoso ... es lo suficientemente grande como para hundir el Titanic.

Parece que Python hizo el truco "Introducción a la programación 101" y simplemente movió todo main()el código a una función diferente llamada algo muy similar a "main".

Aquí está mi pregunta: ¿está este código terriblemente escrito, o hay otras razones para tener una función principal corta?

Tal como está ahora, no veo absolutamente ninguna diferencia entre hacer esto y simplemente mover el código Py_Main()nuevamente main(). ¿Me equivoco al pensar esto?

Riwalk
fuente
44
¿No sería eso mejor para codereviews.stackexchange.com ?
foobar
38
@Luzhin, no. No le pido a nadie que revise el código fuente de Python. Esta es una pregunta de programación.
Riwalk
3
TBH, la mitad del código es el procesamiento de opciones, y cada vez que su programa admite muchas opciones, y escribe un procesador personalizado, esto es lo que termina haciendo ...
Nim
77
@Star No, Programmers.SE también es para mejores prácticas, estilos de codificación, etc. En realidad, para eso visito el sitio.
Mateen Ulhaq
44
@Nim, entiendo que es lo que está haciendo, pero no hay razón para no escribir como options = ParseOptionFlags(argc,argv)donde optionses una structque contiene las variables Py_BytesWarningFlag, Py_DebugFlagetc ...
riwalk

Respuestas:

137

No puede exportar maindesde una biblioteca, pero puede exportar Py_Main, y cualquiera que use esa biblioteca puede "llamar" a Python muchas veces con diferentes argumentos en el mismo programa. En ese punto, se pythonconvierte en otro consumidor de la biblioteca, poco más que un contenedor para la función de la biblioteca; llama Py_Maincomo todos los demás.

Rob Kennedy
fuente
1
Hay una buena respuesta.
Riwalk
26
Supongo que podría ser más exacto decir que no puedes importarlo , @Shoosh. El estándar C ++ prohíbe llamarlo desde su propio código. Además, su vinculación está definida por la implementación. Además, al regresar de mainllamadas efectivas exit, lo que generalmente no desea que haga una biblioteca.
Rob Kennedy
3
@Coder, vea C ++ 03 §3.6.1 / 5: "Una declaración de retorno maintiene el efecto de abandonar la función principal ... y llamar exitcon el valor de retorno como argumento". Consulte también §18.3 / 8, que explica que "los objetos con una duración de almacenamiento estático se destruyen" y "todos los flujos C abiertos ... se vacían" cuando llama exit. C99 tiene un lenguaje similar.
Rob Kennedy
1
@Coder, si las exithojas mainson irrelevantes. No estamos discutiendo el comportamiento de exit. Estamos discutiendo el comportamiento de main. Y el comportamiento de main incluye el comportamiento de exit, sea lo que sea. Eso es lo que hace que no sea deseable importar y llamar main(si hacer algo así es posible o permitido).
Rob Kennedy
3
@Coder, si regresar de mainno tiene el efecto de llamar exita su compilador, entonces su compilador no sigue el estándar. Que la norma dicta tal comportamiento de mainprueba que no es algo especial. Lo especial maines que regresar de él tiene el efecto de llamar exit. (La forma en que lo hace depende de los escritores del compilador. El compilador podría simplemente insertar código en el epílogo de la función que destruye objetos estáticos, llama a atexitrutinas, descarga archivos y termina el programa, lo cual, nuevamente, no es algo que desee en una biblioteca .)
Rob Kennedy
42

No es que no maindeba ser tanto tiempo como debe evitar que cualquier función sea demasiado larga. maines solo un caso especial de función. Las funciones más largas se vuelven muy difíciles de asimilar, disminuyen la capacidad de mantenimiento y, en general, son más difíciles de trabajar. Al mantener las funciones (y main) más cortas, generalmente mejora la calidad de su código.

En su ejemplo, no hay ningún beneficio para mover el código main.

Mark B
fuente
99
La palabra dorada puede ser "reutilizar". Un largo mainno es muy reutilizable.
S.Lott
1
@S - Esa es una palabra de oro. ¡Otro es OMG! TDAH acaba de patear !!!! o en términos simples: legibilidad.
Edward Strange
3
main () también tiene algunas restricciones que otras funciones no tienen.
Martin York
1
También main () no tiene un significado real. Su código debería significar algo para otro programador. Utilizo main para analizar argumentos y eso es todo, e incluso delego eso si son más que unas pocas líneas.
Bill K
@ Bill K: Buen punto, usar main () solo para analizar argumentos (y comenzar el resto del programa) también se ajusta al principio de responsabilidad única.
Giorgio
28

Una razón para main()abreviar implica pruebas unitarias. main()es la única función que no se puede probar por unidad, por lo que tiene sentido extraer la mayoría del comportamiento en otra clase que se puede probar por unidad. Esto va de la mano con lo que dijiste

Escribir código modularizado y seguir el principio de responsabilidad única permitió que mi código se diseñara en "grupos", y main () no sirvió más que como un catalizador para poner en marcha el programa.

Nota: Tengo la idea de aquí .

Oportunidad
fuente
Otra buena Nunca pensé en ese aspecto.
Riwalk
16

Rara vez es una buena idea mainser larga; Al igual que con cualquier función (o método), si es largo, probablemente pierda oportunidades para refactorizar.

En el caso específico que mencionas anteriormente, maines breve porque toda esa complejidad se tiene en cuenta Py_Main; Si desea que su código se comporte como un shell de Python, puede usar ese código sin mucho esfuerzo. (Se debe tener en cuenta de esa manera porque no funciona bien si se coloca mainen una biblioteca; si lo hace, suceden cosas extrañas).

EDITAR:
para aclarar, mainno puede estar en una biblioteca estática porque no tiene un enlace explícito y, por lo tanto, no se vinculará correctamente (a menos que lo coloque en un archivo de objeto con algo a lo que se hace referencia, lo cual es simplemente horrible !) Las bibliotecas compartidas generalmente se tratan como similares (de nuevo, para evitar confusiones), aunque en muchas plataformas un factor adicional es que una biblioteca compartida es solo un ejecutable sin una sección de arranque (de la cual maines solo la última parte y la más visible )

Compañeros de Donal
fuente
1
En resumen, no poner mainen una biblioteca. No funcionará o te confundirá terriblemente. Pero delegar virtualmente todo su trabajo a una función que está en una biblioteca, a menudo es sensato.
Donal Fellows
6

Main debería ser breve por la misma razón que cualquier función debería ser breve. El cerebro humano tiene dificultades para mantener grandes cantidades de datos no particionados en la memoria a la vez. Divídalo en trozos lógicos para que sea más fácil de digerir y razonar para otros desarrolladores (¡y para usted mismo!).

Y sí, su ejemplo es terrible y difícil de leer, y mucho menos mantener.

Ed S.
fuente
Sí, siempre sospeché que el código en sí era terrible (aunque la pregunta se refería a la ubicación del código, no al código en sí). Me temo que mi visión de Python ha sido inherentemente dañada como resultado ...
riwalk
1
@stargazer: No sé si el código en sí es terrible, solo que no está bien organizado para el consumo humano. Dicho esto, hay un montón de código "feo" que funciona bien y funciona muy bien. La belleza del código no lo es todo, aunque siempre debemos hacer todo lo posible para escribir el código más limpio posible.
Ed S.
meh Para mí, son uno y lo mismo. El código limpio tiende a ser más estable.
Riwalk
El código no es terrible, principalmente hay casos de cambio y el manejo de múltiples plataformas. ¿Qué es exactamente lo que encuentras terrible?
Francesco
@Francesco: Lo siento, "Terrible" desde una perspectiva de mantenimiento y legibilidad, no funcional.
Ed S.
1

Algunas personas disfrutan de más de 50 funciones que no hacen nada más, pero envuelven una llamada a otra función. Prefiero preferir la función principal normal que hace la lógica del programa principal. Bien estructurado por supuesto.

int main()
{
CheckInstanceCountAndRegister();
InitGlobals();
ProcessCmdParams();
DoInitialization();
ProgramMainLoopOrSomething();
DeInit();
ClearGlobals();
UnregisterInstance();
return 0; //ToMainCRTStartup which cleans heap, etc.
}

No veo ninguna razón por la que deba envolver algo de eso dentro de una envoltura.

Es puramente un gusto personal.

Descifrador
fuente
1
Porque documenta el código. Puede escribir código de esta manera sin la necesidad (casi) de escribir comentarios. Y cuando cambia el código, la documentación cambia automáticamente :-).
Oliver Weiler
1

Su mejor práctica es mantener TODAS sus funciones cortas, no solo principales. Sin embargo, "corto" es subjetivo, depende del tamaño de su programa y del idioma que esté utilizando.

Mike Miller
fuente
0

No hay ningún requisito para mainser de ninguna longitud, aparte de los estándares de codificación. maines una función como cualquier otra, y como tal, su complejidad debe ser inferior a 10 (o lo que digan sus estándares de codificación). Eso es todo, cualquier otra cosa es bastante argumentativa.

editar

mainNo debería ser corto. O largo. Debe incluir la funcionalidad que debe realizar según su diseño y cumplir con los estándares de codificación.

En cuanto al código específico en su pregunta, sí, es feo.

En cuanto a su segunda pregunta, sí, está equivocado . Mover todo ese código nuevamente a main no le permite usarlo de manera modular como una biblioteca al vincular Py_Maindesde afuera.

Ahora estoy claro?

littleadv
fuente
No pregunté si puede ser largo. Le pregunté por qué no debería ser largo.
Riwalk
¿"Complejidad por debajo de 10"? ¿Hay una unidad de medida para eso?
Donal Fellows
@ Stargazer712 La longitud de la función generalmente también está regulada por los estándares de codificación. Es un problema de legibilidad (y complejidad, por lo general, las funciones largas se ramifican para que la complejidad esté muy por encima de 20), y como dije, mainno es diferente de ninguna otra función a este respecto.
littleadv
@Donal: sí, haga clic en el enlace.
littleadv
Voy a tener que rechazar este brote. Te estás perdiendo por completo la intención de la pregunta.
Riwalk
0

Aquí hay una nueva razón pragmática para mantener el principal corto del Registro de cambios de GCC 4.6.1 :

En la mayoría de los destinos con soporte de sección con nombre, las funciones que se usan solo en el inicio (constructores estáticos y main ), las funciones que se usan solo en la salida y las funciones detectadas como frías se colocan en subsecciones de segmentos de texto separadas . Esto extiende la función -freorder-functions y es controlada por el mismo interruptor. El objetivo es mejorar el tiempo de inicio de grandes programas C ++.

Destacado agregado por mí.

Peter G.
fuente
0

No asuma que solo porque un poco de software es bueno, todo el código detrás de ese software es bueno. Un buen software y un buen código no son lo mismo e incluso cuando el buen software está respaldado por un buen código, es inevitable que en un proyecto grande haya lugares donde los estándares se desvanezcan.

Es una buena práctica tener una mainfunción corta , pero en realidad es solo un caso especial de la regla general de que es mejor tener funciones cortas. Las funciones cortas son más fáciles de entender y más fáciles de depurar, además de ser mejores para apegarse al tipo de diseño de "propósito único" que hace que los programas sean más expresivos. maines, quizás, un lugar más importante para cumplir con la regla, ya que cualquier persona que quiera comprender el programa debe comprender, mainmientras que los rincones más oscuros de la base de código pueden ser visitados con menos frecuencia.

Pero, la base de código de Python no está empujando el código Py_Mainpara jugar esta regla, sino porque no puede exportar maindesde una biblioteca ni llamarla como una función.

Jack Aidley
fuente
-1

Hay varias respuestas técnicas anteriores, dejemos eso de lado.

Un main debería ser corto porque debería ser un bootstrap. El principal debe instanciar una pequeña cantidad de objetos, a menudo uno, que hacen el trabajo. Al igual que en cualquier otro lugar, esos objetos deben estar bien diseñados, cohesivos, acoplados libremente, encapsulados, ...

Si bien puede haber razones técnicas para que una línea principal de una línea llame a otro método monstruo, en principio está en lo correcto. Desde una perspectiva de ingeniería de software, no se ha ganado nada. Si la elección es entre una línea principal que llama un método monstruo y la principal es un método monstruo, este último es fraccionalmente menos malo.

Gannet de hormigón
fuente
Está asumiendo que "el código C ++ debe usar objetos y solo objetos". Eso no es cierto, C ++ es un lenguaje multiparadigm, y no fuerza todo en un molde OO como otros lenguajes.
Ben Voigt