Herramientas AI para Estudiantes
Recursos gratuitos que potencian tu aprendizaje en 2025
Notepad++
LIGEROEditor de código ligero y potente para Windows. Ideal para edición rápida de archivos.
Flameshot
SCREENSHOTSHerramienta de capturas de pantalla con anotaciones. Ideal para documentar código y bugs.
PowerShell 7+
TERMINALShell moderno y multiplataforma de Microsoft. Automatiza tareas y scripts avanzados.
VS Code for the Web
NAVEGADORVisual Studio Code directamente en tu navegador. Sin instalación, desde cualquier lugar.
Google Colab
NOTEBOOKSJupyter Notebooks en la nube gratis. GPU incluida para Machine Learning y Data Science.
AntiGravity AI
PRODUCTIVIDADAsistente IA para productividad y automatización de tareas. Potencia tu flujo de trabajo.
DeepL Translate
TRADUCCIÓNEl mejor traductor con IA. Ideal para documentación técnica y papers académicos.
DeepSeek
OPEN SOURCEModelo de IA chino de código abierto. Excelente para código y razonamiento matemático.
Claude
AI ASSISTANTAsistente de IA de Anthropic para resolver dudas, explicar código y aprender conceptos.
Le Chat (Mistral AI)
ECONÓMICOAsistente IA francés, potente y accesible. Ideal para estudiantes con presupuesto limitado.
GitHub Copilot Pro
GRATISTu programador par con IA. Sugerencias de código en tiempo real directamente en tu editor.
GitHub Student Pack
100+ TOOLSPack exclusivo con herramientas profesionales gratuitas para estudiantes verificados.
Videos Educativos
Tutoriales, conferencias y cursos seleccionados para tu aprendizaje
Fundamentos de Hardware
7 videos
14:43How do SSDs Work?
Branch Education
21:46How does Computer Memory Work?
Branch Education
25:29How do Graphics Cards Work?
Branch Education
15:43How does Bluetooth Work?
Branch Education
12:18How does a Smartphone Camera Work?
Branch Education
19:34How does a CPU Work?
Branch Education
12:45How do Touchscreens Work?
Branch EducationTutoriales de Programación
4 videos
6:14:07Python Full Course for Beginners
Programming with Mosh
2:30:48Java Tutorial for Beginners
Programming with Mosh
4:20:37SQL Tutorial - Full Database Course
freeCodeCamp
3:26:42JavaScript Full Course
freeCodeCampArquitectura & DevOps
4 videos
2:46:14Docker Tutorial for Beginners
TechWorld with Nana
3:36:52Kubernetes Tutorial for Beginners
TechWorld with Nana
4:15:30AWS Tutorial For Beginners
Simplilearn
12:35Microservices Architecture
ByteByteGoData Engineering
4 videos
5:18:22Data Engineering Full Course
freeCodeCamp
3:45:10Apache Spark Tutorial
Simplilearn
1:30:45Apache Airflow Tutorial
coder2j
15:42Data Warehouse Concepts
ByteByteGoDesarrollo Web Frontend
6 videos
1:20:47React Tutorial for Beginners
Programming with Mosh
6:31:33HTML & CSS Full Course
SuperSimpleDev
2:22CSS in 100 Seconds
Fireship
8:16:47Node.js and Express.js Full Course
freeCodeCamp
2:06CSS Flexbox in 100 Seconds
Fireship
5:38:45React 18 Full Course
freeCodeCampComputer Science Fundamentals
6 videos
5:22:09Algorithms and Data Structures
freeCodeCamp
1:56:20Big O Notation - Full Course
freeCodeCamp
1:08:29Git and GitHub Crash Course
freeCodeCamp
1:51:38Introduction to Algorithms
CS50
8:03:05Data Structures Easy to Advanced
freeCodeCamp
5:01:39Dynamic Programming - Full Course
freeCodeCampNotion Workspace
Documentación, notas y recursos del curso en tiempo real
Workspace en Construcción
Próximamente: documentación del curso, notas colaborativas, recursos y más
Cuenta Educativa
Notion Plus gratis con tu email .edu o institucional
Templates
Usa templates para notas de clase, proyectos y tracking
Bases de Datos
Organiza tareas, materias y calificaciones con databases
Colaboración
Comparte páginas con compañeros para proyectos grupales
Conexión a PostgreSQL
Conectar a base de datos PostgreSQL con psycopg2
import psycopg2
from psycopg2 import sql
# Conexión a la base de datos
conn = psycopg2.connect(
host="localhost",
database="mi_base_datos",
user="usuario",
password="password"
)
# Crear cursor
cursor = conn.cursor()
# Ejecutar query
cursor.execute("SELECT * FROM usuarios WHERE activo = %s", (True,))
resultados = cursor.fetchall()
# Cerrar conexión
cursor.close()
conn.close()
API REST con FastAPI
Endpoint básico con FastAPI
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class Usuario(BaseModel):
nombre: str
email: str
edad: int | None = None
@app.get("/usuarios/{usuario_id}")
async def obtener_usuario(usuario_id: int):
# Lógica para buscar usuario
return {"id": usuario_id, "nombre": "Juan"}
@app.post("/usuarios/")
async def crear_usuario(usuario: Usuario):
# Lógica para crear usuario
return {"mensaje": "Usuario creado", "data": usuario}
Análisis de Datos con Pandas
Operaciones comunes de DataFrame
import pandas as pd
import numpy as np
# Leer CSV
df = pd.read_csv('ventas.csv')
# Explorar datos
print(df.head()) # Primeras 5 filas
print(df.info()) # Tipos de datos y nulos
print(df.describe()) # Estadísticas básicas
# Filtrar datos
ventas_altas = df[df['monto'] > 1000]
ventas_2024 = df[df['fecha'].str.startswith('2024')]
# Agrupar y agregar
por_region = df.groupby('region').agg({
'monto': ['sum', 'mean', 'count'],
'cliente': 'nunique'
}).round(2)
# Crear columnas calculadas
df['margen'] = df['venta'] - df['costo']
df['rentabilidad'] = (df['margen'] / df['venta'] * 100).round(2)
# Exportar
df.to_csv('reporte.csv', index=False)
df.to_excel('reporte.xlsx', sheet_name='Ventas')
List Comprehensions y Generators
Patrones Pythónicos para transformar datos
# List Comprehension - crear lista filtrada
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares = [n for n in numeros if n % 2 == 0] # [2, 4, 6, 8, 10]
# Transformación con comprehension
cuadrados = [n**2 for n in range(1, 6)] # [1, 4, 9, 16, 25]
# Dictionary Comprehension
usuarios = ['ana', 'luis', 'carlos']
usuarios_dict = {u: len(u) for u in usuarios}
# {'ana': 3, 'luis': 4, 'carlos': 6}
# Generator Expression (memoria eficiente)
suma_millones = sum(x**2 for x in range(1_000_000))
# Generator Function con yield
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for num in fibonacci(10):
print(num) # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
Encapsulamiento - Clase con atributos privados
POO Pilar 1: Proteger datos internos con getters/setters y validación
/**
* Encapsulamiento: Ocultar implementación interna
* Atributos privados + métodos públicos de acceso
*/
public class Empleado {
// Atributos privados - no accesibles directamente
private String rut;
private String nombre;
private double salario;
private boolean activo;
// Constructor con validación
public Empleado(String rut, String nombre, double salario) {
this.setRut(rut); // Usa setter para validar
this.nombre = nombre;
this.setSalario(salario);
this.activo = true;
}
// Getter - acceso controlado de lectura
public String getRut() {
return this.rut;
}
// Setter con validación - control de escritura
public void setRut(String rut) {
if (rut == null || rut.length() < 8) {
throw new IllegalArgumentException("RUT inválido");
}
this.rut = rut;
}
public double getSalario() {
return this.salario;
}
public void setSalario(double salario) {
if (salario < 0) {
throw new IllegalArgumentException("Salario no puede ser negativo");
}
this.salario = salario;
}
// Método de negocio encapsulado
public double calcularSalarioAnual() {
return this.salario * 12 + (this.salario * 0.5); // + aguinaldo
}
}
Herencia - Extensión de clases
POO Pilar 2: Reutilizar código con extends y super()
/**
* Herencia: Crear jerarquías de clases
* Clase hija hereda atributos y métodos de la padre
*/
// Clase padre (superclase)
public class Persona {
protected String nombre;
protected String email;
protected LocalDate fechaNacimiento;
public Persona(String nombre, String email) {
this.nombre = nombre;
this.email = email;
}
public String presentarse() {
return "Hola, soy " + this.nombre;
}
public int calcularEdad() {
return Period.between(fechaNacimiento, LocalDate.now()).getYears();
}
}
// Clase hija (subclase) - hereda de Persona
public class Estudiante extends Persona {
private String matricula;
private String carrera;
private List<String> asignaturas;
// Constructor llama a super() para inicializar padre
public Estudiante(String nombre, String email, String matricula, String carrera) {
super(nombre, email); // Llama constructor padre
this.matricula = matricula;
this.carrera = carrera;
this.asignaturas = new ArrayList<>();
}
// Método propio de Estudiante
public void inscribirAsignatura(String asignatura) {
this.asignaturas.add(asignatura);
}
// Sobrescribir método padre
@Override
public String presentarse() {
return super.presentarse() + " y estudio " + this.carrera;
}
}
Polimorfismo - Múltiples formas
POO Pilar 3: Un mismo método con diferentes comportamientos
/**
* Polimorfismo: "Muchas formas"
* - Sobrecarga: mismo nombre, diferentes parámetros
* - Sobrescritura: @Override en clases hijas
*/
// Clase abstracta base
public abstract class Vehiculo {
protected String marca;
protected String modelo;
public Vehiculo(String marca, String modelo) {
this.marca = marca;
this.modelo = modelo;
}
// Método abstracto - cada vehículo lo implementa diferente
public abstract void acelerar();
// Método concreto heredable
public String getInfo() {
return marca + " " + modelo;
}
}
// Polimorfismo por sobrescritura
public class Auto extends Vehiculo {
private int numeroPuertas;
public Auto(String marca, String modelo, int puertas) {
super(marca, modelo);
this.numeroPuertas = puertas;
}
@Override
public void acelerar() {
System.out.println("El auto acelera con el pedal");
}
}
public class Moto extends Vehiculo {
private int cilindrada;
public Moto(String marca, String modelo, int cc) {
super(marca, modelo);
this.cilindrada = cc;
}
@Override
public void acelerar() {
System.out.println("La moto acelera con el puño");
}
}
// Uso del polimorfismo
public class Main {
public static void main(String[] args) {
// Una variable del tipo padre puede referenciar hijos
List<Vehiculo> vehiculos = new ArrayList<>();
vehiculos.add(new Auto("Toyota", "Corolla", 4));
vehiculos.add(new Moto("Honda", "CBR", 600));
// Cada uno ejecuta SU versión de acelerar()
for (Vehiculo v : vehiculos) {
v.acelerar(); // Polimorfismo en acción
}
}
}
Abstracción - Interfaces
POO Pilar 4: Definir contratos con interface e implements
/**
* Abstracción: Ocultar complejidad, mostrar solo lo esencial
* Interface = contrato que las clases deben cumplir
*/
// Interface define QUÉ hacer, no CÓMO
public interface Registrable {
String obtenerIdentificador();
LocalDateTime getFechaRegistro();
boolean validar();
}
// Interface para persistencia
public interface Persistible {
void guardar();
void eliminar();
void actualizar();
}
// Clase implementa múltiples interfaces
public class Producto implements Registrable, Persistible {
private String codigo;
private String nombre;
private double precio;
private LocalDateTime fechaCreacion;
public Producto(String codigo, String nombre, double precio) {
this.codigo = codigo;
this.nombre = nombre;
this.precio = precio;
this.fechaCreacion = LocalDateTime.now();
}
// Implementación de Registrable
@Override
public String obtenerIdentificador() {
return this.codigo;
}
@Override
public LocalDateTime getFechaRegistro() {
return this.fechaCreacion;
}
@Override
public boolean validar() {
return codigo != null && !codigo.isEmpty() && precio > 0;
}
// Implementación de Persistible
@Override
public void guardar() {
if (this.validar()) {
System.out.println("Guardando producto: " + this.codigo);
// Lógica de persistencia (BD, archivo, etc.)
}
}
@Override
public void eliminar() {
System.out.println("Eliminando producto: " + this.codigo);
}
@Override
public void actualizar() {
System.out.println("Actualizando producto: " + this.codigo);
}
}
SOLID - Single Responsibility (SRP)
Principio SRP: Una clase debe tener una sola razón para cambiar
/**
* SOLID - SRP: Single Responsibility Principle
* ❌ MAL: Una clase hace todo (validación, lógica, persistencia)
* ✅ BIEN: Separar responsabilidades en clases especializadas
*/
// ❌ MAL - Clase con múltiples responsabilidades
public class EmpleadoMalo {
public void guardarEnBaseDatos() { /* SQL aquí */ }
public void validarDatos() { /* Validaciones */ }
public void enviarEmailBienvenida() { /* Email */ }
public double calcularSalario() { /* Cálculo */ }
// Esta clase tiene 4 razones para cambiar!
}
// ✅ BIEN - Responsabilidades separadas
// Solo datos y comportamiento de negocio del empleado
public class Empleado {
private String rut;
private String nombre;
private double salarioBase;
public double calcularSalarioMensual() {
return this.salarioBase;
}
}
// Solo validaciones
public class EmpleadoValidator {
public boolean validar(Empleado empleado) {
return empleado.getRut() != null &&
empleado.getNombre() != null &&
empleado.getSalarioBase() > 0;
}
public List<String> obtenerErrores(Empleado empleado) {
List<String> errores = new ArrayList<>();
if (empleado.getRut() == null) errores.add("RUT requerido");
return errores;
}
}
// Solo persistencia
public class EmpleadoRepository {
public void guardar(Empleado empleado) {
// Solo lógica de base de datos
}
public Empleado buscarPorRut(String rut) {
// Solo consulta BD
return null;
}
}
// Solo notificaciones
public class EmpleadoNotificador {
public void enviarBienvenida(Empleado empleado) {
// Solo lógica de email
}
}
Excepciones Personalizadas
Manejo de errores con excepciones propias del dominio
/**
* Excepciones Personalizadas
* Crear excepciones específicas del negocio para mejor manejo de errores
*/
// Excepción base del dominio
public class NegocioException extends RuntimeException {
private final String codigo;
public NegocioException(String codigo, String mensaje) {
super(mensaje);
this.codigo = codigo;
}
public String getCodigo() {
return codigo;
}
}
// Excepciones específicas
public class EmpleadoNoEncontradoException extends NegocioException {
public EmpleadoNoEncontradoException(String rut) {
super("EMP-001", "Empleado no encontrado con RUT: " + rut);
}
}
public class ValidacionException extends NegocioException {
private final List<String> errores;
public ValidacionException(List<String> errores) {
super("VAL-001", "Errores de validación");
this.errores = errores;
}
public List<String> getErrores() {
return errores;
}
}
// Uso en el servicio
public class EmpleadoService {
private final EmpleadoRepository repository;
public Empleado buscarPorRut(String rut) {
return repository.buscarPorRut(rut)
.orElseThrow(() -> new EmpleadoNoEncontradoException(rut));
}
public void registrar(Empleado empleado) {
List<String> errores = validator.obtenerErrores(empleado);
if (!errores.isEmpty()) {
throw new ValidacionException(errores);
}
repository.guardar(empleado);
}
}
// Manejo en el controller
public class EmpleadoController {
public void buscar(String rut) {
try {
Empleado emp = service.buscarPorRut(rut);
mostrar(emp);
} catch (EmpleadoNoEncontradoException e) {
mostrarError("No encontrado: " + e.getMessage());
} catch (ValidacionException e) {
mostrarErrores(e.getErrores());
}
}
}
Spring Boot Controller
Controller REST básico con Spring Boot
@RestController
@RequestMapping("/api/usuarios")
public class UsuarioController {
@Autowired
private UsuarioService usuarioService;
@GetMapping("/{id}")
public ResponseEntity<Usuario> obtenerUsuario(@PathVariable Long id) {
Usuario usuario = usuarioService.buscarPorId(id);
if (usuario == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(usuario);
}
@PostMapping
public ResponseEntity<Usuario> crearUsuario(@Valid @RequestBody Usuario usuario) {
Usuario nuevo = usuarioService.guardar(usuario);
return ResponseEntity.status(HttpStatus.CREATED).body(nuevo);
}
}
JPA Repository
Interface de repositorio con Spring Data JPA
@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {
// Query methods
Optional<Usuario> findByEmail(String email);
List<Usuario> findByActivoTrue();
// Query personalizada
@Query("SELECT u FROM Usuario u WHERE u.nombre LIKE %:nombre%")
List<Usuario> buscarPorNombre(@Param("nombre") String nombre);
// Query nativa
@Query(value = "SELECT * FROM usuarios WHERE created_at > :fecha",
nativeQuery = true)
List<Usuario> findRecientes(@Param("fecha") LocalDateTime fecha);
}
Crear tabla con constraints
DDL para crear tabla con claves y restricciones
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
fecha_nacimiento DATE,
activo BOOLEAN DEFAULT true,
rol_id INTEGER REFERENCES roles(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT chk_email CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')
);
-- Índices para mejorar rendimiento
CREATE INDEX idx_usuarios_email ON usuarios(email);
CREATE INDEX idx_usuarios_rol ON usuarios(rol_id);
Query con JOIN y agregación
Consulta compleja con múltiples JOINs
SELECT
d.nombre AS departamento,
COUNT(e.id) AS total_empleados,
AVG(e.salario) AS salario_promedio,
MAX(e.salario) AS salario_maximo,
MIN(e.fecha_contratacion) AS primera_contratacion
FROM departamentos d
LEFT JOIN empleados e ON d.id = e.departamento_id
WHERE e.activo = true
AND e.fecha_contratacion >= '2023-01-01'
GROUP BY d.id, d.nombre
HAVING COUNT(e.id) > 5
ORDER BY total_empleados DESC
LIMIT 10;
Fetch API con async/await
Consumir API REST con manejo de errores
async function fetchUsuarios() {
try {
const response = await fetch('https://api.ejemplo.com/usuarios', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching usuarios:', error);
throw error;
}
}
// Uso con POST
async function crearUsuario(usuario) {
const response = await fetch('https://api.ejemplo.com/usuarios', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(usuario)
});
return response.json();
}
React Hook personalizado
Custom hook para manejo de datos
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
async function fetchData() {
try {
setLoading(true);
const response = await fetch(url, {
signal: abortController.signal
});
const json = await response.json();
setData(json);
setError(null);
} catch (err) {
if (err.name !== 'AbortError') {
setError(err.message);
}
} finally {
setLoading(false);
}
}
fetchData();
return () => abortController.abort();
}, [url]);
return { data, loading, error };
}
ES6 Módulos y Clases
Exportar/importar módulos y clases modernas
// usuario.js - Módulo con clase
export class Usuario {
#password; // Campo privado (ES2022)
constructor(nombre, email) {
this.nombre = nombre;
this.email = email;
this.createdAt = new Date();
}
// Getter
get info() {
return `${this.nombre} <${this.email}>`;
}
// Método estático
static validarEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// Método async
async guardar() {
const response = await fetch('/api/usuarios', {
method: 'POST',
body: JSON.stringify(this)
});
return response.json();
}
}
// Función helper exportada
export const formatearFecha = (fecha) =>
new Intl.DateTimeFormat('es-CL').format(fecha);
// Export default
export default Usuario;
// En otro archivo:
// import Usuario, { formatearFecha } from './usuario.js';
Array Methods Funcionales
map, filter, reduce y encadenamiento
const productos = [
{ id: 1, nombre: 'Laptop', precio: 999, stock: 5 },
{ id: 2, nombre: 'Mouse', precio: 29, stock: 50 },
{ id: 3, nombre: 'Teclado', precio: 79, stock: 0 },
{ id: 4, nombre: 'Monitor', precio: 299, stock: 10 }
];
// filter - filtrar elementos
const enStock = productos.filter(p => p.stock > 0);
// map - transformar elementos
const nombres = productos.map(p => p.nombre);
// find - encontrar uno
const laptop = productos.find(p => p.id === 1);
// reduce - agregar a un valor
const totalInventario = productos.reduce(
(total, p) => total + (p.precio * p.stock), 0
);
// Encadenamiento (chaining)
const resumen = productos
.filter(p => p.stock > 0)
.map(p => ({
nombre: p.nombre,
valor: p.precio * p.stock
}))
.sort((a, b) => b.valor - a.valor);
// some / every - validaciones
const hayAgotados = productos.some(p => p.stock === 0);
const todosDisponibles = productos.every(p => p.stock > 0);
Recursos de Aprendizaje 2025
Libros, cursos y comunidades recomendados por la industria
Libros Esenciales
Designing Data-Intensive Applications
La biblia de sistemas distribuidos y arquitectura de datos
Fundamentals of Data Engineering
Guía completa para iniciar en ingeniería de datos
Clean Code
Principios y patrones para escribir código limpio
System Design Interview
Preparación para entrevistas de diseño de sistemas
Plataformas de Cursos
Coursera
CourseraCursos de Google, IBM, Meta y universidades top del mundo
DataCamp
DataCampCursos interactivos de Python, SQL y Data Science
Whizlabs
WhizlabsPreparación para certificaciones cloud AWS, Azure, GCP
freeCodeCamp
freeCodeCampCertificaciones gratuitas en desarrollo web y más