Entradas

Destacado

Antipatrones, Code Smells, ... USTED NO LO HAGA

Acá escribiré mi propia colección de antipatrones o code smells, existen muchos, pero dejaré los que más me llaman la atención (o son más feos) Usar el sufijo Impl Verlo me duelen los ojos, ¿que quieren decir con Impl? nadie lo sabe, ¿no saben que quieren expresar? ¿hay un mal uso de interfaces/implementaciones (muy probable)?, tienen una interface y la unica clase que la implementa es la Impl ¡horrible! ¿problema de diseño?, supongo que tienen claro que no tendrán una nueva implementación, y si la tienen ¿le pondrán Impl2, Impl3?, me imagino que les encantaria tener una interface llamada List y cuando instancian le pondrían List l1 = new ListImpl() o List l2 = new ListImpl2()... Usar el prefijo I en interfaces Es tan desagradable como el anterior, ¿que quieren expresar con eso? ¿no saben que es lo que están diseñando? ¿es una restricción que les imponen? por que realmente no tiene una explicación lógica, tienen que tener claro lo que están representando para poder ...

kafbat: UI para Kafka

Imagen
Anteriormente configuramos Kafka, ahora necesitamos una UI para mirar que pasa en nuestro Kafka 👀 Vamos a utilizar kafka-ui , navegamos a releases y descargamos la última disponible (en este momento la 1.2.0 Ya con el jar en nuestro poder, lo dejamos en la carpeta que consideremos adecuada y creamos el archivo local.yml con el siguiente contenido: kafka: clusters: - name: local bootstrapServers: localhost:9092 logging: level: root: INFO io.kafbat.ui: DEBUG reactor.netty.http.server.AccessLog: INFO org.springframework.security: DEBUG server: port: 8888 spring: jmx: enabled: true dynamic.config.enabled: true Ahora usando Java 21 , ejecutamos lo siguiente: ~/code/jdk/jdk-21.0.7+6/bin/java -Dspring.config.additional-location=./local.yml --add-opens java.rmi/javax.rmi.ssl=ALL-UNNAMED -jar api-v1.2.0.jar Revisamos que funcione en http://localhost:8888 Ya quedó configurado 😉

Usando Kafka localmente

Imagen
En esta entrada dejaremos funcionando Kafka localmente Descarguemos kafka , como normalmente ocurre, hay varias opciones, yo prefiero bajar el binario . Luego extraerlo en donde lo ocuparemos y le podemos crear una carpeta llamada data para lo que viene: Agregar el bin de Kafka al path: export PATH=~/code/kafka/kafka_2.13-3.9.0/bin/:$PATH Configurar los brokers Acá configuraremos 3 brokers, para eso vamos a la carpeta kafka_2.13-3.9.1/config y creamos 3 archivos: kafka1.properties, kafka2.properties y kafka3.properties . NO OLVIDAR, hay que indicar la carpeta donde quedarán los datos (en mi caso es /home/sebastian/code/kafka/data/): kafka1.properties: broker.id=1 log.dirs=/home/sebastian/code/kafka/data/kafka1 listeners=PLAINTEXT://:9092,CONTROLLER://:9192 process.roles=broker,controller controller.quorum.voters=1@localhost:9192,2@localhost:9193,3@localhost:9194 controller.listener.names=CONTROLLER listener.security....

Usando Vault localmente

Imagen
Vault es una herramienta utilizada en varios lugares, así que veamos cómo lanzarlo localmente... Ir a https://developer.hashicorp.com/vault/install para realizar la instalación, hay una gran cantidad de alternativas, en mi caso fue usar la disponible usando el package manager de Linux: al final tiene que quedar disponible el comando vault en el path. Crear una carpeta para los datos, yo creé una llamada vault y dentro de vault una llamada data: Ya en vault, crear el archivo config.hcl con el siguiente contenido: storage "raft" { path = "./data" node_id = "node1" } listener "tcp" { address = "127.0.0.1:8200" tls_disable = "true" } disable_mlock = true api_addr = "http://127.0.0.1:8200" cluster_addr = "https://127.0.0.1:8201" ui = true En la carpeta vault que creamos antes, configurarlo de la siguiente manera: en una terminal ejecutar (podrían guardar el comando en u...

Comparando Strings con ==

Todos aprendimos que para comparar strings utilizamos equals, pero que sucede si ocupamos == ¿? caso 1: los literales son iguales (quedan en el pool de strings), pero al comparar con uno creado con new String() ya no es igual a menos que se use intern: String d = "d"; final String dd = "d"; String ddd = new String("d"); System.out.println("1 true: " + (d == dd)); System.out.println("2 true: " + ("d" == dd)); System.out.println("3 true: " + (""" d""" == d)); System.out.println("4 false: " + ("d" == ddd)); System.out.println("5 true: " + (d == ddd.intern())); caso 2: usando string concatenation, serán iguales si no se concatenan con variables: String ja = "ja"; String va = "va"; ...

Testcontainers + Localstack +AWS Java SDK 2.x

Al usar localstack en las pruebas y el sdk 2.x de AWS para Java no es tan simple como sacar el endpoint y el credential provider de localstack y pasarlo al cliente de aws, hay que constuir primeros los objetos del sdk 2 para pasarlos al cliente con datos que entrega localstack: private static LocalStackContainer ls = null; @BeforeAll public static void before() { ls = new LocalStackContainer(DockerImageName.parse("localstack/localstack")) .withServices(DYNAMODB); ls.start(); final var credentials = ls.getDefaultCredentialsProvider().getCredentials(); final var ddbc = DynamoDbClient.builder() .endpointOverride(ls.getEndpointOverride(DYNAMODB)) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create( credentials.getAWSAccessKeyId(), credentials.getAWSSecretKey()))).build(); } ese el código para construir el cliente de dynamo usan...

Experimento concurrente

En esta entrada dejaré el resultado de un experimento que surgió por una difícil pregunta que me generó varias dudas... El experimento es revisar el comportamiento de un programa usando un Map en forma concurrente: Comenzamos creando la clase con el map, luego agregarle algunos datos y el main: public class Concurrido { private final Map<Integer, String> estado = new HashMap<y>(); { IntStream.rangeClosed(1, 1_000_000) .forEach(i -> estado.put(i, String.valueOf(1))); } public static void main(String[] args) throws InterruptedException { final var c = new Concurrido(); final var t1 = new Thread(() -> { c.m1(); System.out.println("m1 terminado"); }); final var t2 = new Thread(() -> { c.m2(); System.out.println("m2 terminado"); }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("fin"); } el main lanzará 2 hilos...