Job - un modèle de conception pour les programmeurs Go débutants et expérimentés

J'ai commencé à programmer en Go après une assez longue période de programmation en PHP. Je suppose, à en juger par les dernières tendances, que mon cas est loin d'être isolé. Go en général gagne en popularité parmi les développeurs Web.





Donc, je suis dans le monde des gopher. Et que fait un programmeur PHP, gravé au cœur, une fois sur place? C'est vrai, il continue de "bouffer" - en raison de sa déformation professionnelle - mais déjà sur Go, avec toutes les conséquences qui en découlent.





, Go , , SOLID, Dependency Injection . , ( ), , - PHP, ++ Java.





, , . context.Context, ? , PHP . - ! , , PHP , , Go. . , . , proof of concept. Go, .





, , , , : ", , . , ". — . Reddit Go , … . "? ? over-engineering" - . : " . , README.md - ".





Comment les programmeurs voient la solution

, , , .





? - . :





  1. Job - , (task).





  2. -, 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) }.







ping/pong . , — Github .





// 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
}
      
      







C'est l'une des tâches du client, qui traite la réponse entrante du serveur et stocke l'image résultante. La tâche orchestre son exécution - en utilisant la technique de synchronisation ping / pong susmentionnée - avec une tâche qui analyse les fichiers. Il détermine également quand la dernière réponse du serveur est arrivée et quand terminer l'exécution de tout le travail (Job).





Dans quelle mesure cette solution est sur-machinée et dans quelle mesure son utilisation à la place du contexte Le contexte est justifié - laissez le lecteur décider, j'ai exprimé mon opinion sous forme de sarcasme dans l'image ci-dessus.





Passez un excellent week-end Ă  tous et que le pouvoir de pehape soit avec nous dans le monde des gaufres.








All Articles