Saltar al contenido

Reflexiones sobre cinco años de lecciones en ingeniería de software

Cinco años de ingeniería condensados: fundamentos antes que frameworks, confianza por entregas fiables, código para quien venga y sencillez.

4 min de lectura
Una línea de tiempo que muestra el recorrido de un ingeniero de software desde su primer commit hasta convertirse en ingeniero senior, con hitos y lecciones en el camino

Los fundamentos sobreviven a los frameworks

Cada año llega un framework nuevo. Los ingenieros que prosperan son los que entienden los patrones que hay debajo. Los frameworks cambian; las estructuras de datos, los algoritmos, las redes y el pensamiento de diseño de sistemas siguen siendo relevantes durante décadas.

tstypescript
// The framework changes. The pattern doesn't.
 
// 2020: Express middleware
app.use((req, res, next) => {
  const start = Date.now();
  res.on("finish", () => {
    console.log(`${req.method} ${req.path} - ${Date.now() - start}ms`);
  });
  next();
});
 
// 2023: Next.js middleware
export function middleware(request: NextRequest) {
  const start = Date.now();
  const response = NextResponse.next();
  response.headers.set("X-Response-Time", `${Date.now() - start}ms`);
  return response;
}
 
// 2025: Whatever comes next — still request interception,
// still wrapping the handler, still measuring duration.
// The framework is syntax. The pattern is knowledge.

El código se lee más de lo que se escribe

El código ingenioso no impresiona a nadie seis meses después, cuando hay que depurarlo a las 3 de la madrugada. Escribir pensando en la claridad no es una señal de debilidad: es una señal de experiencia.

tstypescript
// ❌ Clever — what does this do at a glance?
const r = d.filter((x) => x.s === "a" && x.t > Date.now() - 864e5).reduce(
  (a, c) => ({ ...a, [c.c]: (a[c.c] || 0) + c.v }),
  {} as Record<string, number>
);
 
// ✅ Clear — intention is obvious without comments
const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
 
const activeTransactions = deposits.filter(
  (deposit) =>
    deposit.status === "active" && deposit.timestamp > oneDayAgo
);
 
const totalsByCategory = activeTransactions.reduce<Record<string, number>>(
  (totals, transaction) => ({
    ...totals,
    [transaction.category]:
      (totals[transaction.category] ?? 0) + transaction.value,
  }),
  {}
);

Entrega poco, pero entrega seguido

Los pull requests grandes se quedan días esperando revisión, acumulan conflictos de merge y terminan desplegándose con errores ocultos. Los cambios pequeños y enfocados se revisan en minutos y se despliegan con confianza.

tstypescript
// Deployment metrics that tell the story
interface DeliveryMetrics {
  // Small PRs: reviewed faster, fewer bugs
  avgPRSize: { lines: number; reviewTimeHours: number; bugRate: number };
 
  // Deployment frequency: more deploys = smaller blast radius
  deploysPerWeek: number;
 
  // Lead time: commit to production
  leadTimeHours: number;
 
  // Recovery: how fast you fix things when they break
  meanTimeToRecoveryMinutes: number;
}
 
// What I've seen across teams:
const highPerformingTeam: DeliveryMetrics = {
  avgPRSize: { lines: 150, reviewTimeHours: 2, bugRate: 0.02 },
  deploysPerWeek: 25,
  leadTimeHours: 4,
  meanTimeToRecoveryMinutes: 30,
};
 
const strugglingTeam: DeliveryMetrics = {
  avgPRSize: { lines: 2000, reviewTimeHours: 72, bugRate: 0.15 },
  deploysPerWeek: 1,
  leadTimeHours: 336, // 2 weeks
  meanTimeToRecoveryMinutes: 480, // 8 hours
};
 
// The difference is not talent. It's workflow.

Las pruebas ahorran tiempo — con el tiempo

Escribir pruebas se siente lento hasta la primera vez que una prueba detecta una regresión que, de otro modo, habría llegado a producción. El retorno no es inmediato, pero se acumula.

tstypescript
// The test that pays for itself
describe("checkout price calculation", () => {
  it("applies percentage discount before tax", () => {
    const result = calculateTotal({
      items: [{ price: 100, quantity: 2 }],
      discount: { type: "percentage", value: 10 },
      taxRate: 0.08,
    });
 
    // Without this test, a refactor swapped tax and discount order.
    // That bug would have overcharged every customer by ~1%.
    // This test caught it in CI, saved a production incident,
    // and justified every minute spent writing it.
    expect(result.subtotal).toBe(200);
    expect(result.discountAmount).toBe(20);
    expect(result.tax).toBe(14.4); // 8% of $180
    expect(result.total).toBe(194.4);
  });
});

La mejor arquitectura es la más simple que funciona

La sobreingeniería es el error más común a mitad de carrera. Un monolito soporta más tráfico del que uno imagina. Los microservicios resuelven problemas de organización, no técnicos, a menos que tengas el tamaño de equipo que justifique la sobrecarga operativa.

tstypescript
// Year 1 thinking: "We need microservices for scalability"
// Year 3 reality: "We have 40 services, 3 engineers, and
//                  no one understands the full system"
 
// ❌ Premature microservices for a small team
// services/user-service/
// services/order-service/
// services/payment-service/
// services/notification-service/
// services/inventory-service/
// + Kubernetes, service mesh, distributed tracing, 5 databases
 
// ✅ Modular monolith — same boundaries, fraction of the complexity
// src/modules/users/
// src/modules/orders/
// src/modules/payments/
// src/modules/notifications/
// src/modules/inventory/
// + One database, one deployment, clear module boundaries
// Extract to services WHEN you have the team and traffic to justify it

La comunicación escala; el código no

El techo de impacto de programar sin más es más bajo de lo que parece. Los ingenieros que dan forma a los productos, influyen en la arquitectura y aceleran a sus equipos son los que se comunican bien: en documentos de diseño, revisiones de código, retrospectivas de incidentes y conversaciones del día a día.

tstypescript
// A pull request description that accelerates review
interface EffectivePRDescription {
  what: string;      // What changed
  why: string;       // Why this approach
  how: string;       // Key implementation decisions
  testing: string;   // How you verified it works
  risks: string;     // What could go wrong
  rollback: string;  // How to undo if needed
}
 
// vs. the PR description we've all seen:
// Title: "fix stuff"
// Description: ""
// Files changed: 47
 
// The first one gets reviewed in 20 minutes.
// The second one sits for 3 days.

Invierte en la experiencia del desarrollador

Las herramientas, los scripts y los flujos de trabajo que construyes para ti mismo se acumulan día a día. Una mejora de 30 segundos en tu ciclo de desarrollo ahorra horas a lo largo de un año.

tstypescript
// Small investments that compound
const developerExperienceWins = [
  {
    investment: "Hot reload configured properly",
    timePerOccurrence: "10 seconds saved",
    frequency: "200 times/day",
    annualSavings: "~110 hours/year",
  },
  {
    investment: "One-command database reset with seed data",
    timePerOccurrence: "5 minutes saved",
    frequency: "3 times/week",
    annualSavings: "~13 hours/year",
  },
  {
    investment: "Pre-commit hooks catching lint/type errors",
    timePerOccurrence: "15 minutes saved (no CI round-trip)",
    frequency: "5 times/week",
    annualSavings: "~65 hours/year",
  },
  {
    investment: "Automated PR template with checklist",
    timePerOccurrence: "3 minutes saved",
    frequency: "10 times/week",
    annualSavings: "~26 hours/year",
  },
];

La lección debajo de todas las lecciones

La ingeniería de software no se trata de escribir código perfecto. Se trata de resolver problemas para personas —usuarios, compañeros de equipo y tu propio yo futuro— mientras navegas restricciones de tiempo, conocimiento y complejidad. Los mejores ingenieros no son los que conocen más tecnologías. Son los que, de forma constante, toman buenas decisiones de compromiso, se comunican con claridad y dejan el código mejor de como lo encontraron.

Cinco años, cientos de pull requests, decenas de incidentes en producción, y la habilidad más importante resultó ser el criterio: saber cuándo construir, cuándo comprar, cuándo simplificar y cuándo lanzar. El código es solo el artefacto. Lo que importa es el razonamiento detrás.

Wilfredo Rujel

Wilfredo Rujel

Ingeniero de Software Full Stack

Compartir esta publicaciónX