Building an app - something between DI and globals.

agolangf · · 585 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>After doing some trivial examples in Go I&#39;m going to start building a bigger app in Go. Now if I were using Java, I&#39;d use Spring and have stuff like my data access code and various other service layer type. </p> <p>What&#39;s a good middle ground between going full DI and stuff my service layer into globals. Ideally I&#39;d rather not have to pas every dependency around unless there is some elegant way about it. </p> <p>Thanks</p> <hr/>**评论:**<br/><br/>comrade_donkey: <pre><p>Write constructors that take in dependencies and spew out bootstrapped objects. Then either do DI on those constructors or use higher order functions for dependency management (or something else). Note that DI in Go is not common and depends on reflection, which is very expensive.</p></pre>ishbits: <pre><p>Note that I&#39;m not after real DI, I guess I should have mentioned I am after the idiomatic Go way to do this as my Go app grows larger.</p> <p>I thought higher order functions could come into play here, but haven&#39;t really neen any concrete examples. Will explore that further.</p></pre>weberc2: <pre><p>Maybe this is nit-picking, but DI is very common in Go, and it does not depend on reflection:</p> <p><code>MyStruct{Dep1: Dep{Val: 1}}</code></p> <p>^ That&#39;s dependency injection. There are &#34;DI frameworks&#34; that represent that composition tree in XML, JSON, etc so a program can build the right structure dynamically, but such a framework is not needed for DI.</p> <p>The point is that DI is a general concept in which dependencies are injected into the object (via setters or constructor); the frameworks just automate this project from a data-representation of the dependency tree.</p></pre>m173314: <pre><p>I recommend you this solution: <a href="https://github.com/mtojek/dependency-injection-in-go/" rel="nofollow">https://github.com/mtojek/dependency-injection-in-go/</a></p></pre>jmank88: <pre><p>I&#39;ve been working on <a href="http://go-modules.io" rel="nofollow">http://go-modules.io</a> which may suit your needs</p></pre>dr_borges: <pre><p>I started working on a DI solution which uses constructor functions as the means to provide new/singleton instances of &#34;injectable&#34; types, it essentially applies the solution mentioned by @comrade_donkey as its foundation. though it is reflection based: <a href="https://github.com/drborges/katana" rel="nofollow">https://github.com/drborges/katana</a></p> <p>Note: katana started as a proof of concept and by no means was battle tested.</p></pre>ir8prim8: <pre><p>I like a functional DI approach, where you use first class functions and then in your test, assign a new function as a mock. Overview here: <a href="http://openmymind.net/Dependency-Injection-In-Go/" rel="nofollow">http://openmymind.net/Dependency-Injection-In-Go/</a></p> <p>As a best practice if you pass a golang.org/x/net/context.Context around pretty much everywhere, then storing the DI containers in the context is trivial.</p> <p>One more thought - if you are injecting into a long running process like http handlers, keep in mind you will need to re-inject your containers at request time. In my test server I do this to re-inject every request (s.Manager is my DI container and Router is a gorilla mux Router).</p> <pre><code>func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { r := NewRouter(s.Manager) r.ServeHTTP(w, req) } </code></pre></pre>weberc2: <pre><p>Usually I just build everything in <code>main()</code>:</p> <pre><code>service := Service{ Dep1: Dep{ Filepath: &#34;/some/path&#34;, }, Dep2: AnotherDep{ Val: 0, AnotherVal: 1, }, } </code></pre> <p>If <code>AnotherDep</code> is really complicated or if it defined in a separate package (and all of its clients configure it pretty much the same way) then it probably makes sense to create a function that handles the default configuration (e.g., <code>func NewAnotherDep() AnotherDep</code>).</p> <p>This lets clients use the default if they want, but they can also dive into the internal structure and compose their <code>AnotherDep</code> according to their own requirements (for instance, if <code>AnotherDep</code> depends on a <code>type FileSystem interface { ... }</code>, then <code>anotherdep_test.go</code> could build its <code>AnotherDep</code> with a mocked-out <code>FileSystem</code> instead of using the real one).</p></pre>motojo: <pre><p>The strategy I use in my MVC web applications is to create separate decoupled packages for each of my features so that they are reusable in other projects. I also use abstraction for other people&#39;s packages to ensure if they change, I don&#39;t have to rewrite code. In my main func, I configure each one so I can use them without having to pass them around.</p> <p>This is one example of how I utilize the recaptcha package by haisum: <a href="https://github.com/josephspurrier/gowebapp/blob/master/shared/recaptcha/recaptcha.go" rel="nofollow">https://github.com/josephspurrier/gowebapp/blob/master/shared/recaptcha/recaptcha.go</a></p> <p>I configure it from my config file in the main func: <a href="https://github.com/josephspurrier/gowebapp/blob/master/gowebapp.go#L43" rel="nofollow">https://github.com/josephspurrier/gowebapp/blob/master/gowebapp.go#L43</a></p> <p>I then use it in my controller: <a href="https://github.com/josephspurrier/gowebapp/blob/master/controller/register.go#L50" rel="nofollow">https://github.com/josephspurrier/gowebapp/blob/master/controller/register.go#L50</a></p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

585 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传