Feda /dev/ - No Javascript allowed

Normas
spoiler
Personas non gratas
Memes feda dev




Kaledros

#44969 Ya te digo, llevo dos semanas así que no sé nada de nada, pero lo que he visto es que yo tengo esto:

type book struct {
	id          string
	author       string
	description string
	price       int
	createdAt   time.Time
}

Y si en el mismo package pongo esto:

func (b *book) IsValid() (bool, InvalidReason) {
	if len(a.description) > 50 {
		return false, "Description cannot be more than 50 characters long."
	}

return true, ""
}

Entiendo que dentro de ese isValid() puedo modificar lo que me dé la gana del libro que le paso porque tengo acceso a sus variables aunque las haya definido como privadas. Si en vez de a.description > 50 pongo a.description = "polla" no sirve de nada que el struct y sus miembros sean privados.

2 respuestas
desu

#44970 No es exactamente asi porque en GO tambien tienes la GC. El uso de punteros añade presion sobre la GC. Cuando haces un microbenchmark esto quizas no lo ves, o lo tienes que ver en un tipo de carga especifica.

Tambien si tu tienes un struct de algo como un Mutex, te interesa pasar por referencia para acceder al mutex y no a una copia de este por ejemplo. Lo mismo con otras estructuras que sean punteros.

Pero si, tu mensaje Juan es bastante correcto, en general siempre pasar por copia, ademas hoy en dia, al pasar a la call stack se hace incluso por registro para cosas pequeñas como un int32, int64,... osea que la mayoria de cosas que copias se copian instantaneamente en registro... y vuela.

Esto siempre sera mejor:

struct foo type {
   a int
}

que algo con un puntero, que la GC va a tener que tracear:

struct foo type {
   a *int
}

ademas de las otras implicaciones que puedes tener al tener el puntero.

#44971 A ver, yo por 10k euros le ofrezco a tu equipo un par de sesiones de Golang.

El tema es como digo que GO es un lenguaje con GC y ese es un tema a considerar.
Luego esta el tema de la stack.

El caso que pones se recomeinda usar * porque imaginate que tienes este codigo:

func main() {
   p := &{ a: 10, b :"fooo", c: make([]int, 25) }
}

Por poner un ejemplo, si tu ahora empiezas a pasar esta p copiando de funcion a funcion, vas a estar constantemente copiando el contenido:

func main() {
   p := &{ a: 10, b :"fooo", c: make([]int, 25) }
   a(*p)
   b(*p)
   c(*p)
}

E imaginate que a,b,c son funciones que a su vez pasan p de un lado a otro.

Esto lo que hace es que todo el rato hagas copias.

Si tu utilizas un *p todo el rato.

func main() {
   p := &{ a: 10, b :"fooo", c: make([]int, 25) }
   a(p)
   b(p)
   c(p)
}

El beneficio es que solo dereferenciaras el contenido de p cuando sea estrictamente necesario:

func b() {
   p.c = append(p.c, 123)
}

Vs a estar constantemente dereferenciando, que es lo que le he dicho al fpero de @Soltrac

El problema en este ejemplo NO es copiar, es deferenciar y acceder al valor en este caso dels lice por ejemplo, imaginate que tienes diez mil elementos, tienes que acceder a memoria y luego copiar todo a memoria. esto es carisimo


Tambien entra el tema de que T no es igual a *T. Dentro del sistema de tipado, y esto por ejemplo es importante para diseñar modulos.

En Go si tu has diseñado una funcion asi:

func (b book) IsValid() (bool, InvalidReason) {
	if len(a.description) > 50 {
		return false, "Description cannot be more than 50 characters long."
	}

return true, ""
}

Solo la puedes llamar con book. pero si la diseñas con *book, tienes mas flexiblidad. porque si tienes el * tambien tienes el book, pero si tienes el book no tienes xq tener el *. Es decir, tener el puntero te asegura que si tu has ido pasando una funcion en el call stack siempre modificaras el struct que quieres, vs ir pasando copias.

A veces queires algo immutable, a veces no. La immutabilidad tiene un coste de copia y de acceder a memoria y diseñar tu codigo para que devuelvan las funciones el nuevo struct.

El coste mayor siempre es acceder memoria, tu quieres minimizar el acceso a memoria.
Luego esta el coste de la GC, quieres minimizar el uso de punteros.
Y por ultimo estaria el coste de copiar structs enormes, que esto es raro... pero puede ser si tienes un struct de 10KiB. No se que tamaño respecto a tus caches debe ser el struct para que sea problematico la copia, nunca me ha pasado.

desu
#44971Kaledros:

Y si en el mismo package

#44971Kaledros:

no sirve de nada que el struct y sus miembros sean privados.

estas en el mismo modulo pedazo de anormal.

go no tiene packages, go tiene modulos.

cosas como los paquetes y la encapsulacion se inventaron en 1980, los modulos se inventaron por alla 1984... desde entonces los paquetes y la encapsulacion estan deprecated.

imaginate lo perdido que vas, unos 40 años de malas practicas de programacion en java tienes que olvidar.

como norma general no quieres hacer nada en go como lo harias en java, php, python, js o demas porquerias.

go es un lenguaje para mayores, quieres escribir C con una GC.

2 respuestas
Kaledros

#44973 ¿Cuál es la primera puta palabra de cualquier fichero Go, listo de los cojones?

https://www.golang-book.com/books/intro/11

1 respuesta
desu

#44974 no es lo mismo, pero es la misma palabra.

un package de go y un module es lo mismo, ademas go tiene packages (o modules) y modules.

un package de go y uno de java no es lo mismo xq java no es un module.

pero vamos, esto es un detalle tecnico del build, compilar, sistema de modulos...

te puedes quedar con que un package de go y un package de java no es lo mismo. El concepto de publico y privado no existe como piensas dentro de un package por ejemplo. Que es a lo que iba.

Tu puedes tener un package main con dos archivo, main.go y foo.go. Dentro de main.go tener un struct con cosas "privadas" y dentro de foo.go puedes acceder a ello.
Tu en java no puedes tener un package, y tener 2 clases, y acceder a lo privado de otra clase. Java no tiene modulos. Usa encapuslacion y clases.

Gracias a esto por ejemplo testear en go es muy facil, porque no ensucia la API publica de los modulos(packages).

Esto seria encapuslacion vs modulacion. La encapuslacion es un concepto que en programacion tardo 1 - 2 años en deprecetarse. Cuantas veces se dice que la encapuslacion es buena y clean code? Imaginate lo mal que esta esa gente... no teneis ni puta idea.

Kaledros
#44973desu:

go es un lenguaje para mayores, quieres escribir C con una GC

Este es el problema.

Por lo que he visto en estas dos semanas, Go no está para nada pensado para lo que lo quieren usar. Quieren sustituir el proyecto que tenemos montado en Kotlin + Spring (microservicios y toda la pesca) por uno hecho en Go, y ni el lenguaje está pensado para eso ni hay ecosistema, herramientas o expertise enfocadas a eso. Se empeñan en usar un destornillador para clavar un clavo. Si ya no nos ponemos de acuerdo con la gente que lo está usando ya sobre como hacer el layout del proyecto, porque en Go ni siquiera existe un estándar como el que te da Spring en JVM, imagínate más allá.

Obviamente puedes usar Go para montarte microservicios, enviar mensajes, usar Kafka y lo que te dé la gana, pero mientras la JVM tiene frameworks y herramientas que te solucionan tener que bajar al sótano y te sirven para el 99% de los casos de uso sin problema (y el nuestro está dentro de ese 99%), Go lleva estabilizado desde hace años en unas convenciones alejadas de las que estamos usando.

No sé, no entiendo el cambio y creo que estamos usando mal el lenguaje.

3 respuestas
desu
#44976Kaledros:

creo que estamos usando mal el lenguaje

100%

El problema es que quereis hacer Java (spring) en Go.

En lugar de aprender a programar y usar Go.

#44976Kaledros:

ni el lenguaje está pensado para eso ni hay ecosistema, herramientas o expertise enfocadas a eso

Es que Java y el ecosistema Spring, estan diseñados y hay herramientas para resolver problemas que solo existen en Java y Spring...

Tu en Golang no necesitas el 75% del codigo que usas en java, ni esas herramientas... Porque al no tener Spring no tienes problemas de Spring.

Hacer algo en Go es mil veces mas rapido en cuanto a desarrollo que hacerlo en Java y Spring, pero requiere de programadores que sepan programar.

Y no es tu caso.

1 respuesta
Kaledros
#44977desu:

El problema es que quereis hacer Java (spring) en Go

Premio.

Y por supuesto es una decisión política, hemos intentado hacer pushback y nos han dicho que igual en el futuro volvemos a Kotlin, pero me jode comerme este sapo ahora. Aunque bueno, aprender nunca está de más.

#44977desu:

Tu en Golang no necesitas el 75% del codigo que usas en java, ni esas herramientas... Porque al no tener Spring no tienes problemas de Spring.

Ya, pero Spring, aunque tenga sus historias, te facilita muchísimo las cosas si sabes usarlo, si no te flipas y lo usas sólo como lo que es, un framework que si no le haces perrerías te va a funcionar bien. Y en nuestro proyecto no hace falta exprimir ni de lejísimos al framework, si es una cosa sencillísima (aunque extensa) que funciona casi out of the box. Pero en esas estamos.

kidandcat

#44976 Ese problema siempre lo vais a tener, la cosa es enfrentarlo. Viniendo de X lenguaje (java en este caso) y queriendo moveros a otra cosa conceptualmente diferente, vuestra experiencia va a querer seguir programando como si estuvieseis en Java.

Pero os va a pasar con Go, y con cualquier otro lenguaje que no sea 95% copy&paste de java (ejem C#)

Pero vaya, esas movidas de cambiar codebases de un lenguaje a otro porque a alguien le ha salido del pito son una tontería el 100% de las veces. La única cosa que podría justificarla sería si estuvieseis usando algo que no conoce nadie y no hubiese manera de encontrar mano de obra.

1 respuesta
desu

#44979 Te imaginas a un ingeniero mecanico que antes hacia coches, ahora le pides hacer motos y el tio te hace una moto con cuatro ruedas?

Es que te tienes que reir con los fperos...

Como os puede parecer ya no aceptable o normal hacer esas barbaridades que decis?

Pff... que malos sois, la gente asi sobrais en este gremio.

Kaledros

¿Pero quién ha dicho que queremos usarlo igual?

Tenemos unas constraints, como por ejemplo la inmutabilidad de los modelos de dominio. Esa inmutabilidad te la da JVM/Spring sin hacer absolutamente nada y nos funcionaba de maravilla hasta ahora. De repente nos cambian el lenguaje porque a algún C-level le parece una gran idea y nos piden exactamente lo mismo, algo que no es out of the box en Go y que requiere de otro approach. Y nosotros, que en Semana Santa no sabíamos ni lo que era el mod.go, estamos intentando entender como hacerlo. Pero ya está, nadie dice que intentemos usar Go como usamos JVM, simplemente intentamos resolver un problema que ya estaba resuelto cuando nos han cambiado el lenguaje por uno que por no tener no tiene ni un estándar de layout.

Me la pela fortísimo Go, me la pela que tengas que ser un asperger como Hotz para ser un pro de Go y me la pelan soberanamente los punteros, los módulos y el GC. Yo lo que quiero es no tener que calentarme la cabeza en reinventar una rueda que funcionaba y a ser posible hacerlo de manera que si mañana viene otro tío al menos sepa dónde me quedé.

1 respuesta
Fyn4r

Hablas de programar en go como si fuese diseñar un cohete de spaceX

1 1 respuesta
desu

#44982 Programar en Go, solo apto para genios como Desu, Hotz o Cox.

Que Hotz no programa en Go por cierto.

Te tienes que reir con los fperos del hilo.

Primero te insultan, luego te preguntan.

Un buen golpe de realidad dejar Java y Spring para darse cuenta de quien sabe programar y quien sabe usar anotaciones de Spring sin intender que hace.

Pero mejor culpar a Go y a management.

1 respuesta
Kaledros

#44983 Ni React tampoco, al parecer XDD

desu

luego os sorprendeis cuando encuentro "fallos" de diseño en el kernel, en librerias o frameworks open source, en vuestro tooling favorito como k8s, en proveedores cloud... y lo tengo que arreglar

pero es que aunque todos aqui "programemos", algunos programamos a años luz del resto

B

#44976 ya lo siento, yo estuve en una situación similar (de JS a Go), no quiero aburrirte con detalles pero el resultado fue que solo había una persona que sabía Go, el resto no lo habíamos tocado en la vida, así que tras infinitos dramas volvimos a Kotlin que es lo que sabía hacer todo el mundo y en no más de una semana habíamos recuperado el tiempo perdido

Si total, era una puta api normal, no era crud pero poco más

1
desu

@Juan4k4 hoy he hecho lo de multi proecess safe. no es mucho curro la verdad, al parecer porque la syscall del kernel gestiona los errores por ti... vamos a verlo.

test_safe_file_access.py
➜  py-fcntl python3 test_safe_file_access.py -n 50 --mode safe
➜  py-fcntl ls
.rw-r--r--@ 2.3k desu 22 Apr 22:03 test_safe_file_access.py
.rw-r--r--@    2 desu 22 Apr 22:03 testfilesafe
.rw-r--r--@    0 desu 22 Apr 22:03 testfilesafe.lock

fijaros como con este mal diseño el kernel esta exponiendo en user space un .lock que deberia ser transparente para mi.

yo deberia tener esto con un buen kernel:

➜  py-fcntl python3 test_safe_file_access.py -n 50 --mode safe
➜  py-fcntl ls
.rw-r--r--@ 2.3k desu 22 Apr 22:03 test_safe_file_access.py
.rw-r--r--@    2 desu 22 Apr 22:03 testfilesafe

y mi codigo deberia ser asi:

def kernel_good_safe_file_access(file_path):
    # Access the target file
    with open(file_path, 'r+e') as f:
        content = f.read().strip()
        if content:
            value = int(content)
        else:
            value = 0
        value += 1
        f.seek(0)
        f.write(str(value))
        f.truncate()

simplemente un flag como 'e' de exclusive access o 'l' de lock! eso es todo, y que el kernel automaticamente me wrappee y haga todo.

pues no.

requiero de tener un archivo extra .lock, horrible.

Si corro el modo unsafe:

➜  py-fcntl rm testfile*
➜  py-fcntl python3 test_safe_file_access.py -n 50 --mode unsafe
Traceback (most recent call last):
  File "/Users/desu/repos/personal/py-fcntl/test_safe_file_access.py", line 97, in <module>
    test(num_processes=args.num_processes, target=target)
  File "/Users/desu/repos/personal/py-fcntl/test_safe_file_access.py", line 81, in test
    assert value == str(num_processes), f"{value} != {num_processes}"
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 44 != 50

Y ya esta, tanto drama para un archivo de lock a gestionar mas y un par de syscall mas?

Pues si. Mal diseño.

Si un proceso tiene un lock con fcntl y peta, va a liberarlo automaticamente. esto simplifica el codigo.

en este caso super basico no hay mucho que gestionar pero ahora imaginad orquestracion de multi proceso y multi threading a multi archivo... no es del todo facil.

Conclusion:

def kernel_good_safe_file_access(file_path):
    with open(file_path, 'r+e') as f:
        content = f.read().strip()
        if content:
            value = int(content)
        else:
            value = 0
        value += 1
        f.seek(0)
        f.write(str(value))
        f.truncate()

vs

def safe_file_access(file_path):
    lock_file_path = file_path + '.lock'

with open(lock_file_path, 'w') as lock_file:
    fcntl.flock(lock_file, fcntl.LOCK_EX)

    try:
        with open(file_path, 'r+') as f:
            content = f.read().strip()
            if content:
                value = int(content)
            else:
                value = 0
            value += 1
            f.seek(0)
            f.write(str(value))
            f.truncate()
    finally:
        fcntl.flock(lock_file, fcntl.LOCK_UN)

a ver si alguien me puede ver un bug de concurrencia o paralalelismo que se me haya escapado.

como digo, no quiero entrar en orquestracion, por ejemplo starving o tener timeouts de los procesos si cuesta mucho escribir... hacer todo esto seguro pasa de kernel a user space desgraciadamente.

y si leeis mas sobre el tema, como el link que pase, vereis que no solo es un tema de bloquear, es un tema de I/O y de asincronismo en el kernel.

Si pensais en por ejemplo como se resuelve esto en una DB o similares, al final tienes un buffer / wal, que tratas de resolver los problemas de paralelismo que puedan haber y escribes... eso seria el orchestrador. pero si hacemos esto, ya he pasado de tener 1 proceso, a tener 2 procesos, el que YO quiero y el que ORQUESTA, vs tener 1 proceso yo, y que el kernel haga magia por mi.

2 1 respuesta
Soltrac

Mucho texto

Traber

#44987 Hablas de FPeros pero no eres capaz de solucionar ese problema con un Mutex. Tonto.

1 respuesta
kidandcat

#44981 Si que hay estándares de layouts y tal, lo que pasa es que no se generan por ningún framework o herramienta, pero hay style guides y más documentación:

https://github.com/golang-standards/project-layout

https://go.dev/doc/effective_go

Y si, en go no hay esa inmutabilidad como tal, tienes que buscar la forma gopher de hacerlo (con campos privados en structs o algo similar).

Dicho todo esto, estoy completamente de acuerdo contigo, como ya dije, eso de cambiar de lenguaje porque a un panoli le da por ahi (cuando él ni siquiera programa) pues jode, y la verdad, no creo que se obtenga ninguna ventaja. Pero sucede mucho, una cosa más con la que hay que lidiar 🤷‍♂️

PD: Yo tengo la enorme suerte de tener un crack de CTO, y por ejemplo una de sus premisas es que él no es el que programa, así que no se toma ninguna decisión que afecte de esa forma sin consenso con todo el equipo.

JuAn4k4

#44989 Es un cli, el mutex no sirve ya que serían dos procesos separados los que quieren el acceso al fichero. Pero yo veo ahí mucho código y no se mucho de go, pero diría que se puede hacer con mucho menos.

2 respuestas
Soltrac

Con shared memory mismo te creas un bloqueo exclusivo rápido

1 1 respuesta
desu

#44991 es python cabron, casi todo el codigo es para testear la race condition.

otra cosa seria, imaginate que 2 procesos intentan crear el lockfile al mismo momento, funciona bien ese codigo? un open con 'w' flag es suficiente? mucho detalle bajo nivel a verificar.

#44992 no entiendo lo que dices. la memoria debe persistirse por eso hago un file.

ponme un snippet que funcine por favor.

2 respuestas
Soltrac

#44993 no sé ni lo q quieres hacer....

Como dijo @juan4k4 que querías que 2 cli accedieran a un recurso con acceso exclusivo, cualquier named pipe, shared memory, etc. Te resuelve cualquier acceso exclusivo.

La verdad, no sé ni de qué hablabais xddd

1 respuesta
desu
#44994Soltrac:

La verdad, no sé ni de qué hablabais xddd

eso estaba claro con tu respuesta, igual que el tonto del mutex que imagino que directamente era troll

lo mejor de la cli de python que estoy tocando es que no usa Click ni ninguna libreria, esta todo el parseo hecho a mano, no usa ni argparse que es para parsear argumentos de python... dios mio que puta porqueria de sobre enginieria y clases y mierdas

HAHAHAHAH

B

HAHAHAHAH

JuAn4k4

#44993 jajaja de Python he hecho alguna cosa pero ya se ve que muy poca, algún PR arreglando alguna mierda de otros equipos. La verdad es que se parecen.
Por cierto usar un .lock al final es como usar un lock sobre el fichero, no deja de ser advisory, te lo puedes saltar vaya. ¿ No ?

Mira lo que hace este: https://github.com/untitaker/python-atomicwrites
Aunque no se si es multi proceso o no, creo que si ya que juega moviendo ficheros y escribiendo en uno temporal.

1 respuesta
desu

#44997 go bebe de modula-2 y oberon (Griesemer trabajaba en oberon-2)


es normal que te de un aire a pascal y python, lo que pascal originalmente es mas antiguo tambien copio cosas

nim tambien tiene un aire:

y vlang esta copiando directamente golang

https://github.com/vlang/v/blob/master/examples/get_weather/get_weather.v

Dr_Manhattan

1
Traber

#44991 Otro FP. Me lo vas a decir a mi que tengo en C# montado un sistema de escritura de logs con Mutex precisamente para escribir desde varios procesos al mismo fichero sin que se pisen el cuello el uno al otro.

No si encima tendré que hacer un POC para FPeros.

2 respuestas