Skip to content

Latest commit

 

History

History
337 lines (250 loc) · 6.49 KB

CleanCode.md

File metadata and controls

337 lines (250 loc) · 6.49 KB

Cookbook on Clean & Efficient Code

Jina is designed as a lean and efficient framework. Solutions built on top of Jina also mean to be so. Here are some tips to help you write beautiful and efficient code.

  1. from jina import Document, DocumentArray, Executor, Flow, requests is all you need. Copy-paste it as the first line of your code.

  2. Use Python generator as the input to the Flow. Generator can lazily build Document one at a time, instead of building all at once. This can greatly speedup the overall performance and reduces the memory footprint.

    ✅ Do 😔 Don't
    from jina import Flow, Document
    
    def my_input():
        for _ in range(1000):
           yield Document()
    
    f = Flow()
    with f:
       f.post('/', my_input)
    from jina import Flow, Document, DocumentArray
    
    my_input = DocumentArray([Document() for _ in range(1000)]) 
    
    f = Flow()
    with f:
       f.post('/', my_input)
  3. Set request_size. request_size decides how many Documents in each request. When combining with Generator, request_size determines how long will it take before sending the first request. You can change request_size to overlap the time of request generation and Flow computation.

    ✅ Do 😔 Don't
    from jina import Flow, Document
    
    def my_input():
        for _ in range(1000):
           # big document
           yield Document()
    
    f = Flow().add(uses=...)  # heavy computation
    with f:
       f.post('/', my_input, request_size=10)
    from jina import Flow, Document
    
    def my_input():
        for _ in range(1000):
           # big document
           yield Document()
    
    f = Flow().add(uses=...)  # heavy computation
    with f:
       f.post('/', my_input, request_size=10000)
  4. No need to implement __init__ if your Executor does not contain initial states.

    ✅ Do 😔 Don't
    from jina import Executor
    
    class MyExecutor(Executor):
       def foo(self, **kwargs):
         ...
    from jina import Executor
    
    class MyExecutor(Executor):
       def __init__(**kwargs):
         super().__init__(**kwargs)
    
       def foo(self, **kwargs):
         ...
  5. Use @requests without specifying on= if your function mean to work on all requests. You can use it for catching all requests that are not for this Executor.

    ✅ Do 😔 Don't
    from jina import Executor, requests
    
    class MyExecutor(Executor):
       
       @requests
       def _skip_all(self, **kwargs):
         print('default do sth')
    from jina import Executor
    
    class MyExecutor(Executor):
       @requests(on='/index')
       def _skip_index(self, **kwargs):
         pass
    
       @requests(on='/search')
       def _skip_search(self, **kwargs):
         pass
  6. Fold unnecessary arguments into **kwargs, only get what you need.

    ✅ Do 😔 Don't
    from jina import Executor, requests
    
    class MyExecutor(Executor):
       
       @requests
       def foo_need_pars_only(self, parameters, **kwargs):
         print(parameters)
    from jina import Executor, requests
    
    class MyExecutor(Executor):
       
       @requests
       def foo_need_pars_only(self, docs, parameters, docs_matrix, groundtruths_matrix, **kwargs):
         print(parameters)
  7. To debug an Executor, there is no need to use it in the Flow. Simply initiate it as an object and call its method.

    ✅ Do 😔 Don't
    from jina import Executor, requests, DocumentArray, Document
    
    
    class MyExec(Executor):
    
        @requests
        def foo(self, docs, **kwargs):
            for d in docs:
                d.text = 'hello world'
    
    
    m = MyExec()
    da = DocumentArray([Document(text='test')])
    m.foo(da)
    print(da)
    from jina import Executor, requests, DocumentArray, Document, Flow
    
    
    class MyExec(Executor):
    
        @requests
        def foo(self, docs, **kwargs):
            for d in docs:
                d.text = 'hello world'
    
    
    da = DocumentArray([Document(text='test')])
    
    with Flow().add(uses=MyExec) as f:
        f.post('/', da, on_done=print)
  8. Send parameters only request to a Flow if you don't need docs.

    ✅ Do 😔 Don't
    from jina import Executor, Flow, requests
    
    class MyExecutor(Executor):
       
       @requests
       def foo_need_pars_only(self, parameters, **kwargs):
         print(parameters)
    
    f = Flow().add(uses=MyExecutor)
    
    with f:
       f.post('/foo', parameters={'hello': 'world'})
    from jina import Executor, Flow, Document, requests
    
    class MyExecutor(Executor):
       
       @requests
       def foo_need_pars_only(self, parameters, **kwargs):
         print(parameters)
    
    f = Flow().add(uses=MyExecutor)
    
    with f:
       f.post('/foo', inputs=Document(), parameters={'hello': 'world'})