¿Sacrifico nombres de variables más cortos por un código "en columnas" más largo?

17

Soy un programador aficionado en una clase de CS tratando de aprender habilidades de programación adecuadas. Así es como se ve mi código, sus bordes se extienden a 103 columnas.

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }

Antes de tener esos nombres de variables súper largos, tenía cosas como i, j, k, pero mi profesor insiste en que no debemos usar variables como esa en el "mundo profesional" y que incluso las variables acortadas como lenWord son insuficientes porque la gente podría asumir significa "Literatura mundial de Lennard". Él dice que elija nombres de variables significativos, pero al hacerlo siento que he roto la regla de oro de la codificación para mantenerla en 80 columnas. ¿Cómo puedo evitar esto?

RaulT
fuente
26
Sigue adelante; agregue nombres más útiles. Se puede pensar en una manera de describir cipherColumn + (rowSize*nextWord) + nextWordque deje claro lo que el cálculo es de , por ejemplo? Apuesto a que ese nombre es más corto que el cálculo, por lo que obtienes un beneficio de legibilidad y una longitud de línea reducida. Tampoco alinee las asignaciones, o debe moverlas todas si cambia el nombre de la variable más larga.
jonrsharpe
2
Hmm ... entonces, ¿estás diciendo que debería crear una nueva variable y almacenar el resultado de cipherColumn + (rowSize * nextWord) + nextWord en ella para poder usarla más? ¿Es eso lo que hacen los profesionales? Realmente estoy preguntando
RaulT
8
Sí, esa es mi sugerencia. Soy un profesional y es lo que haría, así que ... algunos de ellos, al menos.
jonrsharpe
11
La regla de oro es escribir código que pueda leerse y entenderse. escribimos código para otras personas (!) no para máquinas. Para las máquinas hay un código de máquina. para algunos, el código que se parece a lo que usted describió (nombres de letras simples, etc.) es una falta de respeto para otros programadores (y para usted en el futuro, porque lo olvidará en las próximas semanas o meses). no hay razón para quedarse con 80 columnas, no es MS DOS en los años 80.
rsm
3
@stijn sí, pero es la última vez que lo necesitamos. al igual que no compilo mi código c para el procesador 8086 de 8 bits en caso de que necesite almacenarlo en tarjetas perforadas, tampoco creo que 80 columnas golden stardard tengan ningún significado en el siglo XXI. deberíamos estirar esta tecnología, no sentarnos en los años 80 y pensar que nos convierte en hackers inteligentes. inteligente es la simplicidad, la legibilidad y la tecnología al máximo. Tenemos monitores full-hd, es hora de usarlo.
rsm

Respuestas:

24

Normalmente cuando veo un código publicado aquí como el tuyo, lo edito, porque odiamos el desplazamiento horizontal. Pero como esa es parte de tu pregunta, te mostraré la edición aquí:

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
}

Esa ruptura puede ser sorprendente, pero es más fácil de leer que la versión con desplazamiento horizontal, y es mejor que acortar los nombres de i, jy k.

No es que nunca se debe utilizar i, jy k. Esos son buenos nombres al indexar 3 forbucles anidados . Pero aquí los nombres son realmente mi única pista sobre lo que esperabas que sucediera. Especialmente porque este código en realidad no hace nada.

La mejor regla a seguir en la longitud del nombre variable es el alcance. Cuanto más viva una variable, más variables compañeras tendrá que competir con su nombre. El nombre CandiedOrange es único en el intercambio de pila. Si estuviéramos en un chat, podrías llamarme "Candy". Pero en este momento, estás en un ámbito en el que ese nombre podría confundirse con Candide , Candy Chiu o Candyfloss . Entonces, cuanto más largo sea el alcance, más largo debe ser el nombre. Cuanto más corto sea el alcance, más corto puede ser el nombre.

La longitud de la línea nunca debe dictar la longitud del nombre. Si siente que es así, busque una forma diferente de diseñar su código. Tenemos muchas herramientas para ayudarlo a hacer eso.

Una de las primeras cosas que busco es un ruido innecesario para eliminar. Lamentablemente, este ejemplo no hace nada, por lo que todo es ruido innecesario. Necesito algo con lo que trabajar, así que primero hagamos que haga algo.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
    return cipherColumn;
}

Ahí, ahora hace algo.

Ahora que hace algo, puedo ver de qué me puedo deshacer. Estas cosas de longitud ni siquiera se usan. Esto continuetampoco hace nada.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Hagamos algunos ajustes menores en el espacio en blanco, porque vivimos en un mundo de control de fuente y es agradable cuando la única razón por la que una línea se informa como modificada es porque está haciendo algo diferente, no porque parte de ella tenga que alinearse en una columna.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn = 0;
    int cipherColumn = 0;
    int offset = 1;
    int nextWord = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Sí, sé que es un poco menos legible, pero de lo contrario enloquecerá a las personas que usan herramientas vdiff para detectar cambios.

Ahora arreglemos estos saltos de línea tontos que tenemos porque estamos tratando de permanecer por debajo de los límites de longitud de línea.

int calcCipherColumn(
        char keyWord[25], 
        char cipherText[17424],
        int rowSize, 
        char message[388]
) {
    int keyColumn = 0;
    int keyOffset = 1;

    int nextWord = 1;
    int cipherColumn = 0;
    int cipherOffset = (rowSize * nextWord) + nextWord;

    char key = keyWord[keyColumn];
    char keyNext = keyWord[keyColumn + keyOffset];

    while (key != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyNext != cipherText[cipherColumn + cipherOffset]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Allí, ahora la lógica en el bucle se centra en lo que cambia en el bucle. De hecho, todo excepto cipherColumnpodría estar marcado final. Y oye! Mira eso. Ahora tenemos espacio para hacerlo.

Todo lo que hice fue agregar 3 variables más, renombrar una y reorganizarlas un poco. Y el resultado simplemente hizo que las líneas fueran lo suficientemente cortas como para caber sin un salto de línea tonto !=.

Claro los nombres keyykeyNext no son tan descriptivos, pero cada uno solo se usa una vez, no viven tanto tiempo y, lo más importante, no están haciendo nada tan interesante en el ciclo. Entonces no necesitan serlo. Al introducir variables adicionales, ahora tenemos espacio para alargar sus nombres si es necesario. Las cosas cambian, por lo que eventualmente tendremos que hacerlo. Si lo hacemos, es bueno que tengamos espacio para respirar.

También me tomé la libertad de mostrarle el estilo variante de la forma 6 de Jeff Grigg de diseñar parámetros de entrada para respetar las restricciones de longitud de línea.

naranja confitada
fuente
¡Guau, eso es descriptivo! Sí, sé que el código realmente no hace nada, probablemente debería haber publicado más que un pequeño fragmento, pero supongo que estaba tratando de tener una idea general de lo que hacen los profesionales con respecto a la longitud de la columna de código y los nombres de variables, ¡pero su respuesta mostró algunos cambios muy dulces que definitivamente implementaré en mis códigos de ahora en adelante! Una pregunta más que tengo es: ¿dónde le parece adecuado hacer saltos de línea? Antes de los operadores? ¿Hay un "estándar" aceptado?
RaulT
1
@RaulT pasa algún tiempo leyendo cualquier base de código en la que estés trabajando. Te dará una idea de lo que puedes usar que no sorprenderá a otros programadores. Siga un documento estándar si tiene uno. Pero lo mejor es preguntar a otros programadores y preguntarles qué tan legibles son sus cosas. Ah, y echa un vistazo a codereview.stackexchange.com
candied_orange
Añadiría un comentario debajo de cipherOffset y explicaría el cálculo porque esa fórmula no es obvia. Olvidarás por qué en tres semanas.
Nelson
15

Otros ya han hecho algunas sugerencias útiles, permítanme resumir:

  • 80 caracteres por línea podrían haber sido una regla de oro en los años 80. Hoy en día, la mayoría de la gente está de acuerdo en que 100 a 130 caracteres están bien.
  • Use saltos de línea dentro de sus expresiones.
  • Divide expresiones largas introduciendo resultados intermedios.

Me gusta agregar otra recomendación: ¡No seas dogmático con los nombres largos! Cuanto mayor es el alcance de una variable, más información debe ponerse en su nombre. Y, en general, es una buena idea mantener pequeño el alcance de las variables.

Por ejemplo, si tiene una variable para la columna de su tabla de cifrado de palabras clave y está claro que solo se usa esta tabla en el alcance de su variable, está bien llamarla columno incluso col. Si el alcance es mayor y hay varias tablas involucradas, tiene sentido llamarlo keyWordEncryptionTableColumn.

Otro ejemplo: si tiene un bucle con un cuerpo que abarca dos o tres líneas y tiene que usar un índice para acceder a elementos de una matriz, no hay nada de malo en llamar al índice i. En este contexto, es mucho más legible (al menos para la mayoría de las personas) que, por ejemplo arrayIndexOfMyVerySpecialDataSet.

Frank Puffer
fuente
1
Estoy de acuerdo con tu respuesta. En el trabajo, utilizamos 80 char / line para c / c ++ por razones heredadas y porque usamos reviewboard. Para los caracteres / línea de C # 100, a veces infringí la regla y supere ligeramente los 100 para mantener la legibilidad.
peval27
¡Guau, qué gran respuesta! Todos estos respondientes han sido geniales, ¡gracias por la ayuda que lo aprecio!
RaulT
Estoy totalmente de acuerdo con presionar la idea de que 80 líneas de caracteres están desactualizadas. Todavía se aplica a ciertos proyectos y lugares (principalmente por consistencia), pero para muchos, es simplemente innecesario. Muchos desarrolladores están usando algo como Visual Studio o IntelliJ en un monitor completo y tienen un segundo monitor para otras cosas (documentación, etc.). Por lo tanto, tienen mucho espacio en la pantalla para su código. Si solo usa 80 caracteres por línea, probablemente tenga una tonelada de espacio no utilizado. ¡Y el límite de 80 caracteres te duele! Especialmente cuando consideras que la lib estándar puede forzar nombres largos.
Kat
1
Mi punto es que en algunos idiomas, realmente no se puede evitar el hecho de que 80 caracteres es una gran limitación. Entonces, ¿por qué tenerlo innecesariamente? También se menciona que casi todos los editores de nombres importantes e IDE tienen una excelente envoltura inteligente de palabras suaves en estos días, lo que le permite no restringir en absoluto las longitudes de línea. Puede dejar que las longitudes de las líneas sean lo que el lector pueda ver. Pueden cambiar el tamaño de su ventana para obtener un resultado más óptimo. Personalmente, he encontrado que este enfoque es ideal a veces. Y aún no me decepcionó cómo funciona esta envoltura suave.
Kat
Siempre que use nombres de variables simples, DEBE estar 100% seguro del alcance. Pasé tres horas para aprender sobre el cierre de JavaScript.
Nelson
3

Generalmente estoy de acuerdo con tu maestro. Sin embargo, si tiene una variable que va a usar mucho en un código muy grande, puede ser mejor usar una forma abreviada para ella después de ser explícito sobre su significado. Como cuando tiene muchas expresiones y asignaciones aritméticas complejas, esas no se leen tan bien con nombres largos de variables.

Sobre delinear:

ExtractMessage(char keyWord[25], char cipherText[17424],
               int rowSize, char message[388]) 

Esto no sirve para nada, solo limitar la longitud de la línea no lo hace más legible. Si quieres que esto sea legible, haz esto:

ExtractMessage(
  char keyWord[25],
  char cipherText[17424],
  int rowSize,
  char message[388]
  )
{

Y luego puede que incluso desee alinear los identificadores de tipo (agregue un espacio después de int). Sin embargo, sea cuidadoso / restrictivo con esquemas de inicializaciones o listas de argumentos como esta:

int keyColumn    = 0;
int cipherColumn = 0;
int offset       = 1;
int nextWord     = 1;

El problema es que cuando cambias un nombre o agregas una variable, es posible que tengas que formatear todo el bloque para mantener el aspecto bonito. No es tanto por el trabajo como por los cambios sin sentido que introduciría, se vería horrible en un sistema de control de versiones. Su compañero de trabajo vería que cambió el archivo y haría una diferencia con la versión anterior para ver lo que hizo. Entonces, cada línea se iluminaría al cambiar, oscureciendo el cambio real. Dependería un poco de la calidad de la herramienta de comparación utilizada, lo malo que sería en realidad, pero en general no es una buena idea hacer que el código sea demasiado personal y / o que el formato de una línea dependa de la otra.

A veces, el bosquejo puede servir para un propósito, si tiene decenas de líneas consecutivas que son casi iguales, será fácil detectar dónde son diferentes si las delinea.

Tenga en cuenta que un lugar de trabajo puede tener algún formateo automático que simplemente erradicará cualquier formateo elegante que haga a su código antes de enviarlo al sistema de control de versiones.

Martin Maat
fuente
1
Personalmente, el primer bloque de código en su respuesta es mucho más legible para mí que el segundo.
Miles Rout
1
nunca haga el tercero, es una pesadilla de mantenimiento mantenerlo así.
Jwenting
3

Descargo de responsabilidad: estoy exagerando un poco aquí para aclarar mi punto. Así que tome cualquier superlativo con un grano de sal.

Su maestro tiene 100% de razón: ya no hay una "regla de oro" de unos 80 caracteres (a menos que esté escribiendo código Linux, claro). Esa regla se estableció debido al tamaño de los terminales en ese momento, pero hoy en día, puede ingresar fácilmente más de 150 caracteres en su ventana de enditor. E incluso si excede ese límite, es de esperar que su editor ajuste suavemente la línea para que no tenga que desplazarse. Y la única razón para no ir más allá de los 80 caracteres fue la necesidad de desplazarse .

Dicho esto, de hecho es necesario no dejar que tus líneas crezcan indefinidamente. Cuanto más larga sea la línea, más difícil será para un humano analizarla. Pero los nombres cortos de variables no son el remedio para el problema de las líneas largas .

El remedio es dividir sus expresiones lógicamente mediante la introducción de variables con nombres aún más adecuados . No intentes ser inteligente con los espacios en blanco. Simplemente identifique cualquier subexpresión que se pueda nombrar adecuadamente y cree una variable para ella. Eso simplifica tanto el código que calcula la variable como el código que usa esa variable .


No es parte de su pregunta, pero me gustaría comentarlo de todos modos: es una muy mala idea alinear verticalmente a sus =operadores.

Hay tres razones para eso:

  1. Editar un bloque que contiene operadores verticalmente alineados es un PITA. Siempre que cambie la longitud de la variable más grande (cambio de nombre, adición, eliminación), debe retocar todas las líneas en el bloque para recuperar nuevamente su diseño "agradable".

    Por supuesto, este problema puede reducirse un poco utilizando un editor competente, por lo que es la razón menor. La verdadera razón es la segunda:

  2. Esos cambios espurios de espacios en blanco introducidos por la realineación no funcionan bien con los sistemas modernos de control de versiones como git. Tienden a crear cantidades significativas de conflictos de fusión donde no ha ocurrido un conflicto real, y donde no se señalaría ningún conflicto si no se usara la alineación. Cada uno de estos conflictos espurios le costará tiempo valioso por nada .

  3. La alineación lleva cero significado semántico . Carece de sentido. No hay nada que pueda entender mejor con la alineación. Cada línea en su bloque necesita leerse sola para comprender lo que hace, la conexión a las líneas de arriba y abajo es de naturaleza puramente sintáctica.

Dado que la alineación no tiene ningún significado semántico, pero produce costos significativos, debe desaprender el hábito antes de que le cueste más tiempo.


Si te gusta tanto el límite de 80 caracteres, prueba alguna programación fortran. Es cierto que los estándares más nuevos han elevado el límite de la línea fortran a 132 caracteres, pero sigue vigente como paralizando la compilación de cualquier programa que exceda el límite. Si eres bueno programando, pronto odiarás fortran, incluido su límite de longitud de línea. Después de eso, te sanarás por el resto de tu vida.

Yo mismo tuve que hacer algo para programar profesionalmente, y te digo que me ha enseñado a odiar ese límite de longitud de línea. No hay absolutamente nada más frustrante que tener que dividir una línea simple y legible en partes solo porque el compilador ya no la compilará correctamente. Y definitivamente hay líneas de código que son más simples cuando se expresan como una sola línea.

cmaster - restablecer monica
fuente
3

Muchas convenciones estilísticas (¡no reglas!) Surgieron a lo largo de los años debido a limitaciones en los entornos de programación. En la época de tarjetas perforadas, que tenía una fuerza límite en el número de caracteres que pueden aparecer en una línea de fuente física (que era la razón por Fortran reservado columna 6 de caracteres de continuación de línea). No fue hace muchas décadas que estaba trabajando en un terminal VT220 ámbar sobre negro de 80x24; Si bien los editores que utilicé no limitaron las líneas a 80 caracteres, la vida era mucho más fácil si hacía todo lo posible para evitar el desplazamiento horizontal.

En versiones anteriores de Fortran (hasta '77, IINM), ni siquiera podía tener identificadores que tenían más de 6 a 8 caracteres de longitud. Incluso ya en los años 80, C solo garantizaría que los primeros 8 caracteres en nombres externos fueran significativos (razón por la cual algunas funciones de biblioteca tienen nombres maravillosamente descriptivos strpbrk)

Por supuesto, dos décadas después del siglo XXI, ya no tenemos esos límites. No hay razón para no usar identificadores más descriptivos.

La cosa es que, en los contextos adecuados, iy jy kson nombres perfectamente razonables y significativas . Si estoy iterando a través de una matriz o un vector en un bucle y solo necesito algo para identificar el elemento actual, ifunciona perfectamente bien. No usaría un nombre como currentElement: no es más significativo en ese contexto , y solo agrega desorden visual.

Dicho esto, su maestro no se equivoca al obligarlo a pensar en términos de nombres más largos y descriptivos para todo : la vida será más fácil para usted si primero adquiere ese hábito y luego aprende dónde economizar según sea necesario. Como alguien que fue a la vez obligado a poner todo en 8 caracteres o menos, definitivamente es mejor errar en el lado de más información de la que menos. A medida que gane más experiencia, aprenderá dónde puede economizar la longitud del identificador y dónde debe ser un poco más descriptivo.

John Bode
fuente
-1

No estoy seguro de si esto funciona para c o no, pero ¿hay alguna manera de dividir las fórmulas en varias líneas? Sé que algo así existe para Python.

Vea si puede comenzar + (rowSize * nextWord) + nextWord]) {en una nueva línea. (Al igual que presione enter en su IDE y vea si lo sangra para que C sepa que la expresión anterior se está completando en la línea actual)

Krio
fuente
1
Sí, esto definitivamente es posible. C reconoce líneas y líneas de código hasta que agregue algo como un punto y coma. El problema con eso es que nuestras funciones no pueden exceder las 50 líneas, y aunque mi código de ejemplo no tiene 50 líneas, es solo una fracción de mi función total. Me siento muy limitado para escribir en un cuadro de 50 por 80, algoritmos con variables significativas que pueden realizar las funciones que también los necesito. Podría seguir almacenando estos largos trozos de código en nuevas funciones, pero siento que terminaré con tantas llamadas a funciones que la gente se perderá leyendo el código.
RaulT
55
"Siento que terminaré con tantas llamadas a funciones que la gente se perderá leyendo el código". ¡Todo lo contrario! Extraer el código en métodos separados le permite darles nombres descriptivos que aumentan la legibilidad (especialmente del método del que está extrayendo). Si terminas con demasiados métodos, tu clase podría estar haciendo demasiado (principio de responsabilidad única). Extraer métodos en una clase separada nuevamente le permite darle a esa cosa un nombre descriptivo.
Roman Reiner
Cualquier función que se aproxime a 50 líneas es probablemente demasiado larga y compleja (con la posible excepción de la inicialización de datos con una complejidad de 1), pero generalmente cuando se discuten límites como ese son líneas de código, no líneas de texto, por lo que se divide una sola línea de código, es decir, el punto y coma a menudo no contará como una línea adicional, consulte con el Prof!
Steve Barnes