Estoy creando un modelo de objeto para un dispositivo que tiene múltiples canales. Los sustantivos utilizados entre el cliente y yo son Channel
y ChannelSet
. ("Conjunto" no es semánticamente preciso, porque está ordenado y un conjunto adecuado no lo es. Pero eso es un problema para un momento diferente).
Estoy usando C #. Aquí hay un ejemplo de uso de ChannelSet
:
// load a 5-channel ChannelSet
ChannelSet channels = ChannelSetFactory.FromFile("some_5_channel_set.json");
Console.Write(channels.Count);
// -> 5
foreach (Channel channel in channels) {
Console.Write(channel.Average);
Console.Write(", ");
}
// -> 0.3, 0.3, 0.9, 0.1, 0.2
Todo es elegante. Sin embargo, los clientes no son programadores y estarán absolutamente confundidos por la indexación cero: el primer canal es el canal 1 para ellos. Pero, en aras de la coherencia con C #, quiero mantener el ChannelSet
índice desde cero .
Esto seguramente causará algunas desconexiones entre mi equipo de desarrollo y los clientes cuando interactúan. Pero peor, cualquier inconsistencia en cómo se maneja esto dentro de la base de código es un problema potencial. Por ejemplo, aquí hay una pantalla de IU donde el usuario final ( que piensa en términos de indexación 1 ) está editando el canal 13:
Ese Save
botón finalmente dará como resultado algún código. Si ChannelSet
es 1 indexado:
channels.GetChannel(13).SomeProperty = newValue; // notice: 13
o esto si es cero indexado:
channels.GetChannel(12).SomeProperty = newValue; // notice: 12
No estoy realmente seguro de cómo manejar esto. Siento que es una buena práctica mantener una lista ordenada de cosas indexadas con enteros (the ChannelSet
) consistentes con todas las otras interfaces de matriz y lista en el universo C # (por indexación cero ChannelSet
). Pero entonces cada pieza de código entre la interfaz de usuario y el backend necesitará una traducción (restar por 1), y todos sabemos lo insidiosos y comunes que ya son los errores off-by-one.
Entonces, ¿alguna vez te ha mordido una decisión como esta? ¿Debo cero índice o un índice?
fuente
Respuestas:
Se siente como si estuvieras combinando el Identificador para el
Channel
con su posición dentro de aChannelSet
. La siguiente es mi visualización de cómo se vería su código / comentarios en este momento:Parece que ha decidido que debido a que las
Channel
s dentro de aChannelSet
se identifican por números que tienen un límite superior e inferior, deben ser índices y, por lo tanto, como se basa en C #, 0. Si la forma natural de referirse a cada uno de los canales es por un número entre 1 y X, consúltelos por un número entre 1 y X. No intente forzarlos a ser índices.Si realmente desea proporcionar una forma de acceder a ellos mediante un índice basado en 0 (¿qué beneficio le da esto a su usuario final o a los desarrolladores que consumen el código?), Implemente un indexador :
fuente
Muestre la IU con el índice 1, use el índice 0 en el código.
Dicho esto, trabajé con dispositivos de audio como este y usé el índice 1 para los canales y diseñé el código para nunca usar "Índice" o indexadores para ayudar a evitar la frustración. Algunos programadores todavía se quejaron, así que lo cambiamos. Luego otros programadores se quejaron.
Solo elige uno y quédate con él. Hay problemas más grandes que resolver en el gran esquema de sacar el software por la puerta.
fuente
Option Base
era tonto, me gustó la característica que ofrecían algunos lenguajes de permitir que las matrices especifiquen individualmente límites inferiores arbitrarios. Si uno tiene una matriz de datos por año, por ejemplo, más allá de poder tener una matriz dimensionada[firstYear..lastYear]
puede ser mejor que tener que acceder siempre al elemento[thisYear-firstYear]
.Usa ambos.
No mezcle la interfaz de usuario con su código central. Internamente (como una biblioteca) debe codificar "sin saber" cómo el usuario final llamará a cada elemento de la matriz. Utilice las matrices y colecciones indexadas 0 "naturales".
La parte del programa que une los datos con la IU, la vista, debe tener cuidado de traducir correctamente los datos entre el Modelo mental del usuario y la 'Biblioteca' que hace el trabajo real.
¿Por qué es esto mejor?
fuente
Puedes ver la colección desde dos ángulos diferentes.
(1) Es, en primer lugar, una colección secuencial regular , como una matriz o una lista. El índice de
0
es obviamente la solución correcta entonces, siguiendo la convención. Usted asigna suficientes entradas y asigna el número de canal a los índices, lo cual es trivial (solo resta1
).(2) Su colección es esencialmente una asignación entre identificadores de canal y objetos de información de canal. Simplemente sucede que los identificadores de canal son un rango secuencial de enteros; mañana podría ser algo así
[1, 2, 3, 3a, 4, 4.1, 6, 8, 13]
. Utiliza este conjunto ordenado como claves de mapeo.Elija uno de los enfoques, documente y manténgalo. Desde el punto de vista de la flexibilidad, iría con (2), porque la representación del número de canal (al menos el nombre mostrado) es relativamente probable que cambie en el futuro.
fuente
channels[int]
) será cero enteros indexados, y los descriptores de acceso GetGetChannelByFrequency
,GetChannelByName
,GetChannelByNumber
será flexible.Dictionary
oSortedDictionary
.operator [] (int index)
debería estar basado en 0, mientrasoperator [] (IOrdered index)
que no lo haría. (Disculpas por la sintaxis aproximada, mi C # está muy oxidado.)[]
en un lenguaje que use esta sobrecarga para buscar mediante una clave arbitraria, los programadores no deben asumir que las claves comienzan0
y son contiguas, y deberían dejar ese hábito de forma aguda. Pueden comenzar desde0
, o1
, o1000
, o la cadena"Channel1"
, ese es el objetivo de usar el operador[]
con claves arbitrarias. OTOH, si se tratara de C y alguien dijera "si dejara el elemento0
en una matriz sin usar para comenzar1
", entonces no diría "obviamente, sí", sería una decisión cercana, pero me inclinaría por "no".Todos y sus perros usan índices basados en cero. El uso de índices basados en uno dentro de su aplicación le causará problemas de mantenimiento para siempre.
Ahora lo que muestra en una interfaz de usuario, eso depende totalmente de usted y su cliente. Simplemente muestre i + 1 como el número de canal, junto con el canal #i, si eso hace feliz a su cliente.
Si expones una clase, la expones a los programadores. Las personas que te confunden con un índice basado en cero no son programadores, por lo que aquí hay una desconexión.
Parece que le preocupa la conversión entre la interfaz de usuario y el código. Si eso le preocupa, cree una clase con la representación de interfaz de usuario de un número de canal. Una llamada que convierte el número 12 en la representación de la interfaz de usuario "Canal 13", y una llamada que convierte el "Canal 13" en el número 12. De todos modos, debe hacerlo, en caso de que el cliente cambie de opinión, por lo que solo hay dos líneas de código cambiar. Y funciona si el cliente solicita números romanos o letras de la A a la Z.
fuente
Estás mezclando dos conceptos: indexación e identidad. No son lo mismo y no deben confundirse.
¿Cuál es el propósito de la indexación? Acceso aleatorio rápido. Si el rendimiento no es un problema, y dada su descripción no lo es, entonces el uso de una colección que tiene un índice es innecesario y probablemente accidental.
Si usted (o su equipo) está confundido por el índice frente a la identidad, entonces puede resolver ese problema al no tener un índice. Use un diccionario o un enumerable y obtenga el canal por valor.
El primero es más claro, el segundo es más corto: pueden traducirse o no al mismo IL, pero de cualquier manera, dado que está usando esto para un menú desplegable, debería ser lo suficientemente rápido.
fuente
Está exponiendo una interfaz a través de su
ChannelSet
clase con la que espera que sus usuarios interactúen. Lo haría lo más natural posible para ellos usarlo como sea posible. Si espera que sus usuarios comiencen a contar desde 1 en lugar de 0, exponga esta clase y su uso teniendo en cuenta esa expectativa.fuente
La indexación basada en 0 fue popular y defendida por personas importantes, porque la declaración muestra el tamaño del objeto.
Con las computadoras modernas, con las computadoras que usarán sus usuarios, ¿es importante el tamaño del objeto?
Si su idioma (C #) no admite una forma limpia de declarar el primer y último elemento de una matriz, puede declarar una matriz más grande y usar constantes declaradas (o variable dinámica) para identificar el inicio y el final lógicos de El área activa de la matriz.
Para los objetos de IU, es casi seguro que puede permitirse usar un objeto de diccionario para su mapeo (si tiene 10 millones de objetos, tiene un problema de IU), y si el mejor objeto de diccionario resulta ser una lista con espacio desperdiciado en cada extremo, no has perdido nada importante.
fuente