Resumen práctico | Recuerde la reconstrucción del microcódigo en un requisito de iteración

Hola a todos, soy Dan Dan, el ingeniero de tecnología front-end de la plataforma empresarial DingTalk. En el pasado, después de experimentar asistencia, registro, aprobación, plataforma abierta, banco de trabajo y otros negocios clave de DingTalk, el intercambio era más arquitectura técnica o pensamiento comercial. Esta vez, solo registré un nivel micro de las necesidades diarias ordinarias de los programadores. .Proceso de reconstrucción.

Antecedentes de la demanda

Una página es como se muestra a la izquierda. El requisito es mover la parte en el cuadro rojo a la posición señalada por la flecha roja para lograr el efecto que se muestra a la derecha.

necesita valoración

Antes de ver el código de la página original, puede pensar que se trata de un requisito menor. ¿No sería bueno si se movieran los componentes de la página? Los requisitos se completan rápidamente, la parte comercial está satisfecha y todos tenemos un futuro brillante. Después de leer el código, de repente me sentí ingenuo. No es tan simple como cree y es fácil cometer errores. Para describir claramente los motivos, a continuación se utilizan abreviaturas y no es necesario comprender el significado comercial.

Para cumplir con este requisito, se deben hacer estas tres cosas:

1. Encuentra la ubicación de destino

2. Encuentre el componente objetivo

3. Mover

Primero analicemos la estructura de la página actual: Página La página contiene dos componentes A y B. El componente A tiene dos subcomponentes a1 y a2. La posición de destino está entre a1 y a2. La posición de destino es muy clara. El problema está en B. La parte de b1 que se va a mover está dentro del componente B, pero b1 no es un componente, sino un montón de código dentro de B. Hay dos componentes AR y HR en la lógica b1. Uno de ellos puede mostrarse o no mostrarse en diferentes condiciones. Y b1 depende de 10 atributos del contexto B. Si el objetivo b1 no es un componente, la complejidad del movimiento es UPUP.

Representación del código de la parte b1:

.../** b1部分的代码 */let hRecord = null;const hasSupplySuite = hasSupplySuite();if (type === TypeENUM.REPAIR_CHECK && data && !hasSupplySuite) {hRecord = (<ARecordid={originatorInfo.workNo}pId={pId}/>);} else if (hasSupplySuite || type > 1) {hRecord = (<HRecordpId={pId}id={originatorInfo.workNo}count={currentCount}name={schema.title}username={originatorInfo.name}isLeave={type === TypeEnum.LEAVE}code={formData.code.value}/>);}if (!isUserInList() || location.href.indexOf('list') !== -1) {hRecord = null;}...

Si trasplanta la lógica de b1 del componente B al componente A, debe prestar atención a estos 10 parámetros. Es como mover 10 cajas de diferentes formas de la habitación B a la habitación A a través de la ventana (API del componente), no hay herramienta de transporte, por lo que solo puedes moverlas una por una. La ventana de A y la ventana de B son diferentes en tamaño y forma, y ​​es posible que algunas no encajen, lo que requiere que A expanda la ventana. Sacar el rábano y sacar el barro es un proceso difícil de realizar sin cometer errores.

Ya existen más de 30 API para los componentes A y B. Se estima que los requisitos se han superpuesto uno tras otro a lo largo de los años. Si es necesario superponer más API para este requisito como es habitual, se debe tener cuidado para evitar omisiones y conflictos.

Este enfoque es muy desagradable y no favorece la futura expansión, sino que cava el agujero cada vez más profundo. El corazón de la reconstrucción está listo para moverse.

Por supuesto, cuando se enfrente a la opción de refactorizar, habrá muchas ideas, como:

1. Los beneficios de la refactorización generalmente se obtienen en el futuro, ¿ es necesario hacerlo ahora ?

2. Refactorizar me lleva mucho tiempo, pero aumentar la legibilidad del código sólo reduce los problemas para otros. Puede que no tenga ningún beneficio real para mí. ¿Debería hacerlo?

3. La refactorización también puede causar errores y problemas innecesarios, ¿ tengo que asumir este riesgo?

Estas también pueden ser parte de las razones por las que el código antiguo de la aplicación se deteriora. pero:

1. Si no hay refactorización, el mal olor en el código se cansará cada vez más y el desarrollador será como entrar en una habitación llena de basura;

2. Si no se refactoriza, otros deberán comprenderlo nuevamente si cambian esta parte del código en el futuro, lo que aumentará el costo general de I + D para el equipo;

3. Si no reconstruyes, te sentirás muy culpable por dentro;

Propósito de refactorización

Para controlar el costo de tiempo y minimizar el alcance de la reconstrucción, es necesario aclarar los objetivos de este tiempo en torno a los requisitos.

Objetivo: Facilitar el cumplimiento de este requisito.

Esto requiere tres cosas:

1. Convierta de forma independiente la parte b1 en un componente compatible con dispositivos móviles para reducir el costo de los dispositivos móviles.

2. Mejore la legibilidad del código dondequiera que vaya y reduzca el costo de comprender el código.

3. No cambia la función original.

Proceso de refactorización

Tenga mucho cuidado al refactorizar código antiguo. Diseñe los pasos de refactorización, cada paso es un pequeño cambio independiente, de modo que cada paso pueda probarse y el código de cada paso pueda usarse para reducir la probabilidad de errores.

Analice la lógica del código de la parte b1, que hace referencia a dos componentes, ARecord y HRecord, denominados AR y HR. RR.HH. es un componente independiente. AR está escrito en el componente B. Dado que b1 debe empaquetarse en un componente, AR debe empaquetarse primero de forma independiente.

1. Haga que el componente AR sea independiente en lugar de estar adjunto a B

Primero, saque el código AR de B, modifíquelo ligeramente, encapsule la API y agregue la definición de tipo. Utilice el contexto para representar información de contexto que hace referencia al host del componente. Por ejemplo, puede colocar la información de origen de la página incrustada en este objeto. componenteProps representa los datos del componente. Este paso es relativamente simple.

El código original está en B:

class ARecord extends React.Component {openARecord = () => {const openUrl = `${getBaseUrl()}#/list`;openLink(openUrl);}render() {return (<div className="content" onClick={this.openARecord}>      ...</div>);}}

Nuevo código:

// 从AFlow中将ARecord迁移出来稍加改造// 组件接口定义interface IARecordProps {  className?: string;  style?: object;context: IContextModel;// 本组件的数据componentProps: {id: string;pId: string;  }}
export default function ARecord(props: IARecordProps) {const {    className,    style = {},    context = {},componentProps,  } = props;
const {    utSpace,  } = context;
const {    id,    pId,  } = componentProps;
const openARecord = (id: string, pId: string) => {const openUrl = `${getBaseUrl()}#/arecordlist`;openLink(openUrl);};
return <div className="content"     onClick={() => openARecord(id, pId)}  >  ...  </div>;}

2. Prueba de función de página

Agregue el atributo de contexto al componente B en la página, haga referencia al nuevo componente AR en su ubicación original en el componente B, transfiera datos de acuerdo con la API AR y pruebe la lógica de la página. Prueba aprobada.

3. Tanto AR como HR tienen las condiciones para moverse y comenzar a empaquetar componentes b1.

Este paso es un poco complicado, principalmente porque el código b1 y el componente B están demasiado acoplados. Hay propiedades y métodos que dependen de ello. Comencemos primero con el panorama general, dejando de lado los atributos que se utilizaron originalmente. Primero defina la API externa del nuevo componente, que corresponde al componente original sin cambios. Debido a que no hay una definición de tipo en el código original, todavía lleva algún tiempo determinar de qué tipo es el atributo original.

Simplemente agregue la definición de tipo.

El diseño de API es muy importante al encapsular componentes. Estoy más acostumbrado a encapsular partes que son fáciles de cambiar, como diseñar la API del componente como dos objetos, contexto y componentesProps, que representan el contexto del host y los datos del componente respectivamente. El host es simple y claro de usar. Si agrega nuevos atributos más adelante, solo necesita agregar lógica de procesamiento de datos. No es necesario cambiar el código en la parte de la plantilla. El código parece conciso y el costo de modificación es menor.

// b1组件数据模型定义interface IHRecordSummaryData {hasSupplySuite: ()=>boolean;id: string;pId: string;type: TypeEnum;data: {};count: number;name: string;username: string;code: string;isUserInList: ()=>boolean;}// b1组件数据API定义interface IHRecordSummaryProps {  className?: string;  style?: object;context: IContextModel;// 本组件的数据componentProps: IHRecordSummaryData;}

Convenientemente, cambie la declaración if elseif en la lógica original por una declaración de guardia, que es sencilla y más fácil de entender. Otra lógica interna lo deja en paz.

export default function HRecordSummary(props: IHRecordSummaryProps) {  const {    context,    componentProps,  } = props;
  const {    id,    pId,  } = componentProps || {};
  const getComponentNode = (componentProps: IHRecordSummaryData) => {    const {      hasSupplySuite,      id,      pId,      type,      data,      count,      name,      username,      code,      isUserInList,    } = componentProps || {};
    const aRecordData = {      id,      pId,    }
    if (type === TypeENUM.REPAIR_CHECK && data && !hasSupplySuite) {      return  <ARecord        context={context}        componentProps={aRecordData}      />;    }         if (hasSupplySuite || type > 1) {      return  <HRecord        pId={pId}        id={id}        count={count}        name={name}        username={username}        isLeave={type === TypeEnum.LEAVE}        code={code}      />    }      if (!isUserInList || location.href.indexOf('list') !== -1) {      return null;    }  };
  return <div>    {getComponentNode(componentProps)}  </div>;}

4. Prueba de función de página

Haga referencia al componente b1 en la ubicación original de B, ensamble los datos de componenteProps de acuerdo con la definición del tipo de datos del componente y pruébelo. Prueba aprobada.

B encapsula los datos pasados ​​a b1:

...    const context = {      utSpace: context?.utSpace,    };    const hRecordSummaryData = {      id: originatorInfo?.workNo,      pId: pId,      hasSupplySuite: hasSupplySuite(),      type: type,      data: data,      count: currentCount,      name: schema?.title,      username: originatorInfo?.name,      code: formData?.code?.value,      isUserInList: isUserInList(),    };...
return (  ...    <HRecordSummary      context={context}      componentProps={hRecordSummaryData}    >    </HRecordSummary>  ...)

5. El componente b1 tiene problemas con el diseño de API

Hay un total de 10 atributos dependientes originales que se transfieren. Dado que los 10 atributos originales se pasan de la página a B a través de 10 API y luego de B a b1, será más conveniente encapsularlos en un objeto. La expansión futura lo hará Solo es necesario agregar la lógica del campo de extensión, sin modificar el código en la parte de la plantilla. Si es adecuado encapsularlo en un objeto depende de si estos 10 se usan en otros lugares. Al buscar en el código de B, otra lógica usa solo 1 de los 10 atributos, y el resto solo se usa en b1. Puedes encapsularlo primero.

Primero, combine las 10 API de B en 1 API, el tipo es objeto, con un total de 10 atributos, obtenga este objeto de B y páselo a b1.

Luego, ensamble este objeto en Page y páselo a B. Al mismo tiempo, elimine las 9 API adicionales originales de B. Recuerde conservar 1 que sea utilizada por otra lógica. Para B, se agregó 1 nueva API y se eliminaron 9. Las API de B se redujeron de 37 a 29 y el código también fue más limpio.

6. Prueba de función de página

Cambie los 10 atributos pasados ​​de Página a B y luego a b1 en 1 objeto y pruebe. Prueba aprobada.

7. Confundido acerca de la definición de tipo del componente b1

Se pasaron dos métodos en los atributos originales de b1 y se movieron como estaban. Mirando el código, estos dos métodos no están relacionados con el contexto actual. Puede cambiarlo para pasar solo el valor booleano del resultado del método. No es necesario pasar un método.

8. Prueba de función de página

Cambie los dos métodos que se pasan de Page a B y luego a b1 a valores booleanos y pruébelos. Prueba aprobada.

9. datos en la definición del tipo de componente b1

Diseñe únicamente las API necesarias para los componentes y no transfiera datos redundantes.

Al observar el código, de manera similar, uno de los atributos, los datos, solo se usa en juicios condicionales y solo su existencia se usa como condición, pero la cantidad de datos en sí no es pequeña. De hecho, se puede cambiar a un valor booleano.

10. Prueba de función de página

Cambie los datos pasados ​​de la página a B y luego a b1 a un valor booleano y pruebe. Prueba aprobada.

11. En la actualidad, se cumplen las condiciones para el movimiento rápido de componentes.

En este punto, el código ya tiene las condiciones para mover el componente rápidamente. Será más fácil de operar más adelante. Agregue la misma definición de tipo de datos de componente a ApproveHead, pase los datos de ApprovePage a ApproveFlow a ApproveHead y cambie la referencia del componente de ApproveFlow a ApproveHead. El requisito se cumple.

12. Prueba de función de página

Prueba de regresión de la función de página, la prueba pasó.

Resumir

Un buen código siempre es agradable a la vista y los lectores pueden llegar fácilmente a un acuerdo con el autor. Cada requisito es una oportunidad para mejorar el código antiguo. Insista en escribir código que sea fácil de entender y modificar, e incorpore la refactorización en cada iteración de requisitos para evitar que el código se corrompa con el tiempo.

Sin embargo, las iteraciones de la demanda tienen ciclos y no pueden ser completamente disruptivas en todo momento. Determine el propósito de cada refactorización y deténgala con moderación, lo que puede respetar el ritmo del negocio y optimizarlo. Conforme pase el tiempo, las cosas cambiarán.

"Cualquier tonto puede escribir un programa que una computadora pueda entender. Sólo un programa que los humanos puedan entender fácilmente es un buen programador." - Martin Flower

Haga clic para probar el producto en la nube de forma gratuita ahora y comenzar su viaje práctico en la nube.

Enlace original

Este artículo es contenido original de Alibaba Cloud y no puede reproducirse sin permiso.

Lei Jun anunció la arquitectura completa del sistema ThePaper OS de Xiaomi, diciendo que la capa inferior ha sido completamente reestructurada. Yuque anunció la causa de la falla y el proceso de reparación el 23 de octubre. Nadella, CEO de Microsoft: Abandonar Windows Phone y el negocio móvil fue una decisión equivocada Las tasas de uso de Java 11 y Java 17 excedieron a Java 8. Hugging Face tuvo restringido el acceso a Yuque. La interrupción de la red duró aproximadamente 10 horas y ahora ha vuelto a la normalidad. La Administración Nacional de Datos presentó oficialmente Oracle. Lanzó la extensión de desarrollo de Java para Visual Studio Código Musk: Done mil millones si Wikipedia pasa a llamarse "Enciclopedia Weiji" USDMySQL 8.2.0 GA
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/yunqi/blog/10123316
Recomendado
Clasificación