Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  1. Usage of instance methods to essentially access static fields. Not a big issue and for some may not be an issue at all, but worth pointing out as it may be confusing to others.
  2. Repetitive code in getRelationships() and getSupportedPropertyDescriptors()
  3. Because instance methods are used to access documentable elements, an instance of the component must be created. This fact presents a number of issues:
    1. Security. As NiFi evolves it is conceivable to assume that at some point one of the security requirements could be that an instance of a component may only be created by an authorized principal (e.g., run as)
    2. Questionable code in default constructor. Unrelated (un-used) and poorly implemented component may render the entire system unavailable by having "questionable code" inside the constructor. And while "questionable code" can also be present in static initializer and cause the same issues during class loading, it's a less common pattern and falls in realm of general coding practices (outside of NiFi).
    3. Throwaway instances. In fact NiFi instance without a flow will create and throw away 2 instances of each discovered component, regardless of how many will actually be used. And if component is already in the canvas and part of the flow 5 instance of it will be created (see 
      Jira
      serverASF JIRA
      serverId5aa69414-a9e9-3523-82ec-879b028fb15b
      keyNIFI-1318
      )
    4. Leaky abstractions (of sort):
      1. developer now must be aware that they should not implement default constructor or any constructor for that matter.
      2. if they do they must be aware of any potential side-effects of creating multiple instances of a component, since component is naturally singleton in the process space.
  4. Reliance on the ServiceLoader to discover components.
    1. Current extension model of NiFI assumes local availability of extensions (e.g., some local dir such as 'work') where they can be discovered. ServiceLoader helps with such discovery. But one of the side-effects of the ServiceLoader is a subsequent creation of a component's instance, regardless if the actual instance needs to be created. 

    2. As NiFi moves toward the concept of an ExtensionRegistry the assumptions of having components available locally is no longer valid, since implementation of ExtensionRegistry may not be based on locally available components. 

  5. Generation of all documents during NiFi startup
    1. While current model works for a current state/size of NiFi, it is unsustainable for both NiFi distribution and NiFi documentation when one deals with thousands of components, versions etc.

Possible improvements

  1. To

...

  1. embrace convention over configuration approach which if addressed properly would greatly simplify user(dev) experience and would help to address the following:
    1. Confusion with using instance methods to access static fields. User would no longer have to implement those methods and they can be deprecated.
    2. Repetitive code in getRelationships() and getSupportedPropertyDescriptors().
      1. Analyzing many processors it becomes clear that the code in these methods is very repetitive as seen in example below. A very typical pattern is to assemble Collection in init() method or default constructor, leaving getRelationships() and getSupportedPropertyDescriptors() to simply return the instance variable representing such collections: 

        Code Block
        @Override
        protected void init(final ProcessorInitializationContext context) {
            final List<PropertyDescriptor> descriptors = new ArrayList<>();
            descriptors.add(FILE_SIZE);
            descriptors.add(BATCH_SIZE);
            descriptors.add(DATA_FORMAT);
            descriptors.add(UNIQUE_FLOWFILES);
            this.descriptors = Collections.unmodifiableList(descriptors);
            final Set<Relationship> relationships = new HashSet<>();
            relationships.add(SUCCESS);
            this.relationships = Collections.unmodifiableSet(relationships);
        }
        @Override
        protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
            return descriptors;
        }
        
        @Override
        public Set<Relationship> getRelationships() {
            return relationships;
        }
      2. Repetitive code could be easily handled by Reflection-based mechanisms already used by NiFi and many other projects and products. An example of one such way could be seen here (NIFI-1384 PR). Further more, for enhanced control over which element are meant to be documented, a new @Documentable annotation could be introduced. This would remove a burden from the user to implement these methods making component development much simpler.
  2. While we can recommend best practices, developers could feel free to implement default constructor as they wish with realization that if they do something "questionable" in it, it will have no impact on the overall system until such component is introduced in the process space, at which point its an expression of intent to use.

  3. . . . MORE TO COME. . .

...