Comecei a programar em Go após um longo período de programação em PHP. Suponho que, a julgar pelas últimas tendências, meu caso está longe de ser isolado. Go, em geral, está ganhando popularidade entre os desenvolvedores da web.
Então, estou no mundo gopher. E o que um programador de PHP, totalmente queimado, faz uma vez lá? Isso mesmo, ele continua a "bufar" - devido à sua deformação profissional - mas já em marcha, com todas as consequências que se seguem.
, Go , , SOLID, Dependency Injection . , ( ), , - PHP, ++ Java.
, , . context.Context, ? , PHP . - ! , , PHP , , Go. . , . , proof of concept. Go, .
, , , , : ", , . , ". — . Reddit Go , … . "? ? over-engineering" - . : " . , README.md - ".
, , , .
? - . :
Job - , (task).
-, L4; , backend ; backend , . Job. Github.
Job - Command pattern, . :
Parallel Processing Where the commands are written as tasks to a shared resource and executed by many threads in parallel (possibly on remote machines; this variant is often referred to as the Master/Worker pattern)
, - — . , , context.Context, , . task.Assert
if err != nil { panic(err) }.
// Saves resized image to the output dir
func (s *ImageResizer) SaveResizedImageTask(j job.Job) (job.Init, job.Run, job.Finalize) {
// Do some initialization here
init := func(t job.Task) {
if _, err := os.Stat(s.inputDir); os.IsNotExist(err) {
t.Assert(err)
}
if _, err := os.Stat(s.outputDir); os.IsNotExist(err) {
err := os.Mkdir(s.outputDir, 755)
t.Assert(err)
}
}
run := func(task job.Task) {
stream := j.GetValue().(netmanager.Stream)
select {
case finishedTask := <- j.TaskDoneNotify(): // Wait for the scanner task to be done
if finishedTask.GetIndex() == s.scanneridx {
s.scandone = true
}
task.Tick()
case frame := <-stream.RecvDataFrame(): // Process response from the backend server
task.AssertNotNil(frame)
res := &imgresize.Response{}
err := frame.Decode(res)
task.Assert(err)
baseName := fmt.Sprintf("%s-%dx%d%s",
res.OriginalName, res.ResizedWidth, res.ResizedHeight, res.Typ.ToFileExt())
filename := s.outputDir + string(os.PathSeparator) + baseName
if ! s.dryRun {
ioutil.WriteFile(filename, res.ImgData, 0775)
}
j.Log(1) <- fmt.Sprintf("file %s has been saved", filename)
stream.RecvDataFrameSync() // Tell netmanager.ReadTask that we are done processing the frame
s.recvx++
task.Tick()
default:
switch {
case s.scandone && s.recvx == s.sentx: // Check if all found images were processed
task.FinishJob()
default:
task.Idle() // Do nothing
}
}
}
return init, run, nil
}
Esta é uma das tarefas do cliente, que processa a resposta recebida do servidor e armazena a imagem resultante. A tarefa orquestra sua execução - usando a técnica de sincronização ping / pong mencionada anteriormente - com uma tarefa que faz a varredura de arquivos. Também determina quando veio a última resposta do servidor e quando concluir a execução de todo o trabalho (Job).
Até que ponto esta solução é sobredimensionada e até que ponto seu uso em vez de contexto. Contexto é justificado - deixe o leitor decidir, expressei minha opinião na forma de sarcasmo na imagem acima.
Tenham um ótimo final de semana a todos e que o poder da pehape esteja conosco no mundo dos esquilos.