Hace algunos años escuché una frase que quedó marcada en mi corazón: “¿Por qué hacer las cosas difíciles si las podemos hacer fáciles?”. La persona que me lo dijo se refería a cómo a veces complicamos nuestro trabajo, cuando en realidad existen formas más simples y eficientes de lograr lo mismo.
Contenido
En los últimos días he estado trabajando en transformar mi proyecto Capstone de BYU-Idaho a Nest.js (Backend), y el uso del CLI ha sido clave. Me ha permitido generar módulos, controladores y servicios de forma rápida. Si hubiera escrito todo línea por línea, me habría tomado mucho más tiempo. La clave está en aprovechar las herramientas disponibles para mejorar y acelerar el desarrollo de software.
¿Cómo mejorar tu productividad como desarrollador?
1. Usa el CLI para aprender y producir más rápido
Cuando estás aprendiendo un framework, como Nest.js, usar su CLI es una gran idea. Te ayuda a entender la estructura del proyecto, cómo se organizan los módulos, controladores y servicios. Una vez que comprendas los conceptos básicos, puedes seguir usándolo para ahorrar tiempo y enfocarte en mejorar otras áreas del código.

2. Mejora las funciones de tu código
En artículos anteriores hablé sobre el principio “Don’t Repeat Yourself” (DRY). En mi proyecto actual, he creado servicios reutilizables como:

– Generador de códigos OTP
import { Injectable } from '@nestjs/common';
@Injectable()
export class OtpCodeService {
constructor() {}
generateOtpCode(maxLength: number = 6): string {
const min = Math.pow(10, maxLength - 1); // Mínimo valor para la longitud especificada
const max = Math.pow(10, maxLength) - 1; // Máximo valor para la longitud especificada
return Math.floor(min + Math.random() * (max - min + 1)).toString();
}
}– Hashing y verificación de contraseñas
import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcryptjs';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
@Injectable()
export class HashPasswordsService {
constructor(
) {}
async hashPassword(passwordToHash: string, security: number = 12): Promise<string> {
const hashedPassword = await bcrypt.hash(passwordToHash, security);
return hashedPassword;
}
async verifyPassword(dataBasePassword: string, passwordToCheck: string): Promise<boolean> {
return await bcrypt.compare(passwordToCheck, dataBasePassword);
}
}– Validadores de formato de email
import { Injectable } from '@nestjs/common';
@Injectable()
export class EmailValidatorService {
isValid(email: string): boolean {
// Basic regex for validating an email address
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}– Envío de correos electrónicos
import { Injectable } from '@nestjs/common';
import * as nodemailer from 'nodemailer';
import { EmailLog } from './models/email-log.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
@Injectable()
export class MailService {
private transporter: nodemailer.Transporter;
constructor(
@InjectRepository(EmailLog)
private emailLogRepository: Repository<EmailLog>,
) {
this.transporter = nodemailer.createTransport({
host: process.env.NODEMAILER_HOST,
port: process.env.NODEMAILER_PORT ? parseInt(process.env.NODEMAILER_PORT) : 587,
secure: process.env.NODEMAILER_SECURE === 'true', // <-- CORRECTO
auth: {
user: process.env.NODEMAILER_USER,
pass: process.env.NODEMAILER_PASSWORD
},
connectionTimeout: 100_000,
greetingTimeout: 100_000,
socketTimeout: 100_000
});
}
async sendEmail(emailTo: string, emailSubject: string, emailBody: string): Promise<{sent: boolean, error?: string | null}> {
const emailLog = new EmailLog();
emailLog.emailTo = emailTo;
emailLog.emailSubject = emailSubject;
emailLog.emailBody = emailBody;
try {
const mailOptions = {
from: process.env.NODEMAILER_USER,
to: emailTo,
subject: `${emailSubject} | ${process.env.APP_NAME} System`,
html: `
<h1 style='text-align: center;'>${emailSubject}</h1>
<hr />
${emailBody}
<hr />
<p style='text-align: center;'><strong>${process.env.APP_NAME}®</strong> System </br>© ${new Date().getFullYear()} <a href="https://marbust.com" style="font-weight: bold;">Marbust Technology Company</a> - All Rights Reserved</p>
`,
};
//console.log(`Data for transporter: ${JSON.stringify(this.transporter)}`);
const info = await this.transporter.sendMail(mailOptions);
console.log("Info: ", info);
console.log(`Email was sent to: ${emailTo} with Id: ${info.response}`);
emailLog.result = true;
emailLog.messageId = info;
await this.emailLogRepository.save(emailLog);
return {
sent: true,
error: null,
}
} catch (error) {
console.log(error);
emailLog.result = false;
await this.emailLogRepository.save(emailLog);
return {
sent: false,
error: 'Error sending email',
}
}
}
async sendTestEmail(request: any): Promise<{sent: boolean, error?: string}> {
const { secret, email } = request;
if (!secret || !email) {
return {
sent: false,
error: 'Secret and email are required',
}
}
if (secret !== process.env.JWT_SECRET) {
return {
sent: false,
error: 'Invalid secret',
}
}
// Puedes personalizar el asunto y cuerpo del correo
const {
sent,
error
} = await this.sendEmail(
email,
'Test Email',
'This is a test email sent from the /mail/test endpoint.'
);
if (sent) {
return {
sent: true
}
} else {
console.error('Error sending test email:', error);
return {
sent: false,
error: 'Error sending test email',
}
}
}
}– Firma y validación de JWTs
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { JwtGenerated } from './models/jwt-generated.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService,
@InjectRepository(JwtGenerated)
private readonly jwtGeneratedRepository: Repository<JwtGenerated>,
) {}
async signPayload(payload: any, secretKey?: string): Promise<string> {
// Save the payload in the database
const jwtGenerated = new JwtGenerated();
jwtGenerated.payload = JSON.stringify(payload);
jwtGenerated.expiration = new Date(Date.now() + 3600000);
await this.jwtGeneratedRepository.save(jwtGenerated);
return this.jwtService.sign(payload, {
secret: secretKey ? secretKey : process.env.JWT_SECRET,
expiresIn: '1h',
});
}
verifyToken(token: string, secretKey?: string): any {
try {
return this.jwtService.verify(token, { secret: secretKey ? secretKey : process.env.JWT_SECRET });
} catch (err) {
if (err.name === 'TokenExpiredError') {
console.error('Token has expired.');
} else if (err.name === 'JsonWebTokenError') {
console.error('Invalid token.');
} else {
console.error('Token verification failed.');
}
throw new Error('Token verification failed.');
}
}
}– Validación de roles de usuario
// filepath: d:\Repositories\MarbustSystem\src\services\check-access\check-access.service.ts
import { Injectable, ForbiddenException } from '@nestjs/common';
@Injectable()
export class CheckAccessService {
checkAccess(decodedToken: any, minimumRole: number): void {
console.log(">>> Inside checkAccess, decodedToken: ", decodedToken);
console.log(">>> Inside checkAccess, minimumRole: ", minimumRole);
if (!decodedToken) {
throw new ForbiddenException('Not authenticated.');
}
if (!decodedToken.roleId) {
throw new ForbiddenException('Role not found in JWT.');
}
if (decodedToken.roleId < minimumRole) {
throw new ForbiddenException('Unauthorized access.');
}
}
}– Inserción de datos en lote en la base de datos
import { Injectable, OnModuleInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Role } from '../../users/models/role.entity';
@Injectable()
export class RoleService implements OnModuleInit {
constructor(
@InjectRepository(Role)
private readonly roleRepository: Repository<Role>,
) {}
async onModuleInit() {
const roles = [
{ name: 'User' },
{ name: 'Supervisor' },
{ name: 'Admin' },
{ name: 'Superadmin' },
];
for (const role of roles) {
const existingRole = await this.roleRepository.findOne({ where: { name: role.name } });
if (!existingRole) {
await this.roleRepository.save(role);
}
}
}
}Este enfoque te permite reutilizar código en distintos controladores y mantener todo más limpio y eficiente.
3. Aprovecha GitHub al máximo
No te limites a crear un repositorio y trabajar solo sobre la rama principal. Usa GitHub como una herramienta profesional:
- Crea issues para funcionalidades específicas
- Asígnate tareas
- Crea ramas para cada funcionalidad
- Realiza pull requests con seguimiento del proceso
Esto no solo te ayuda a organizarte mejor, sino que también mejora tu experiencia y documentación del proyecto.

4. Usa Copilot y otras herramientas de IA
GitHub Copilot es una herramienta poderosa (¡y gratuita para muchos estudiantes y desarrolladores!) que puede ayudarte con autocompletaciones y sugerencias inteligentes. No dependas al 100%, pero sí úsalo como apoyo. Te puede ahorrar tiempo, darte ideas y mejorar tu productividad.

5. Encuentra un equilibrio en tu vida
Desarrollar puede ser adictivo y muy gratificante, pero también es importante dedicar tiempo a tus seres queridos. El tiempo no vuelve. Mira una película, juega algo, sal con amigos. A veces, desconectarte también ayuda a pensar mejor, liberar estrés y encontrar nuevas ideas.

Conclusión
Espero que estas ideas te sirvan para convertirte en una mejor versión de ti como desarrollador. La felicidad también está en el equilibrio y en usar bien las herramientas que tienes a tu alcance.
Recuerda que subo videos ocasionalmente a mi canal de YouTube y escribo artículos como este en mi blog. ¡Te invito a darte una vuelta!
Sobre el Autor:

Marco Antonio Bustillos Quiroz
Bachelor of Science in Web Design and Development (BYU-Idaho)
Full Stack Web Developer con más de 7 años de experiencia en desarrollo Front End y 5 años en desarrollo Back End. Mis proyectos incluyen sitios web, landing pages, aplicaciones web, REST APIs, e-commerce, y mucho más. Mi pasión es crear experiencias digitales impactantes y compartir conocimientos con otros desarrolladores.