The company I work for recently started our implementation of Oracle’s Agile PDM/PLM system.

A PLM (product lifecycle management) system is a (usually) software application that guides an organization through the lifecycle of a product. This includes all aspects of design, production, and continuous management of a product. PDM (product data management) concerns the aspects of storing and managing product data, especially changes over time.

Finding Limitations

Over the past few weeks of implementation, we’ve already run into several limitations of Agile. One of them is very low granularity of item attributes.

Agile has two object classes: part and document. Each of these has its own set of attributes applied to all its instances. For example, everything that is a part has a weight attribute and individual dimension attributes. Any custom attributes you add at the “part” level will be applied to anything under the umbrella of “part”.

Parts also can have subclasses. A subclass could normally just be a single attribute, one that contains multiple “tags” or a single list value. Agile uses this special subclass attribute to provide another level of granularity in spawning more specific attributes to a part instance.

An example for subclasses would be a resistor subclass. A resistor instance would not only have the weight and dimension attributes inherited from the “part” level, but also subclass specific attributes inherited from the subclass, like a resistance value (10 Ohms, 100 kOhms) and type (wire-wound, chip, etc.).

This abstraction seems to hold well for a few large groups of well defined objects. Unfortunately, if you have two groups that are similar to each other, but not similar to the rest of the groups, you either end up duplicating attributes across subgroups, or polluting the global attribute list with attributes that don’t apply to the majority of parts.

Designing My Own System

I was unhappy with not having infinite granularity in parts. So the other weekend, I woke up on Saturday morning and designed the schema for a simple proof-of-concept Rails app that had the flexibility I expected Agile to have.

I called it Flexible Parts, and I worked on it furiously for two days. The design requirements were as follows:

  • A part has a number and a name.
  • A part can have any number of attributes.
  • A part has its own unique values for its attributes.
  • Attributes can be shared across parts or unique to a part.
  • Attributes can be organized into “groups” in order to facilitate setup of a new part.
  • When selected, attribute groups attach their attributes to a part, but individual attributes can be removed.

The overall goals I was shooting for were:

  • There should be no compromises made in being able to capture all data relevant to a part in a way that is structured and searchable. Nothing should be left out because it doesn’t “fit” the way the system is laid out (flexibility is the #1 priority).
  • Parts only have the attributes that are relevant to them. There is no need to display irrelevant attributes or leave blank values during part creation.
  • Attributes are not free form, but shared across parts. They must be descriptive enough so that a user could be sure any existing attribute they added to a part was actually the same usage as it was created for.
  • The workflow for creating a new part that is similar to an existing part should be dead simple, either through attribute groups or copying relevant attributes from the similar part.
  • The workflow for creating a new part that is NOT similar to an existing part should seamlessly guide the user through creating the proper attribute groups so that future parts will be even simpler.
  • Searching across attributes should be intuitive.
  • Comparing shared attributes across parts should also be intuitive.
Schema generated by Rails ERD
Schema generated by Rails ERD

Implementation

I made a list of the conceivable features for a first release, then assigned a priority for each based on wanting to give a demo on Monday to the members of my implemenation group.

I compromised on the following:

  • Attributes are only allowable as string value and not boolean, numerical, list, or any other storage type.
  • Only certain aspects of the models are directly editable through the UI.
  • New parts can’t be added through the UI.
  • New attributes can’t be added through the UI.
  • Attribute groups can’t be modified through the UI.
  • There is no search interface.

Regarding new attributes being added to parts, I consider this interface to be critical to the success of the app. Attributes should always be reused across parts (with the condition that the attribute really is describing the same characteristic of both parts). Although new attributes can be created, searching should occur in the list of already existing attributes before a new attribute is created to avoid duplication.

I didn’t get a chance to get this feature the way I wanted. I had to settle for a simple list box of all attributes not already applied to the part. I did experiment with different UX concepts, including modal dialogs, but nothing stuck and the JavaScript pinned me down once more.

Screenshots

Parts index page
Parts index page
Choose trait groups using a chosen plugin type-ahead text box
Choose trait groups using a chosen plugin type-ahead text box
Fill in trait values, and add more from another chosen type-ahead text box
Fill in trait values, and add more from another chosen type-ahead text box
Viewing a single part. I was planning on having the `global|plier` radio buttons filter their traits and values, but did not get around to implementing it.
Viewing a single part. I was planning on having the `global|plier` radio buttons filter their traits and values, but did not get around to implementing it.
All trait groups. Trait groups can keep track of which parts they are attached to.
All trait groups. Trait groups can keep track of which parts they are attached to.
A single trait group. It shows its linked traits and associated parts.
A single trait group. It shows its linked traits and associated parts.

The Outcome

Sunday night ran up on me pretty fast, but I did get most of the critical features up and running. What I was really shooting for was to show the paradigm of flexibility of attributes. I showed it to my group members during a break, and I’m not sure they had their heads wrapped around the problem I originally presented to appreciate the solution I proposed. I got some “that’s cool”s and “you must not be married or have kids” comments when I mentioned I did it over the weekend. Besides that, we moved on with the implementation and made the compromises we needed to.

I’m pleased with the work I did, though. I learned about a bunch of new gems through drone.bz, including migrant, chosen, best-in-place, and even rails-erd (entity relationship diagram – see the figure above). I got much more versed in writing HAML, using Twitter Bootstrap, and getting my first taste of SCSS and SASS (and even Coffeescript). Unfortunately, I’m still very much untrained in writing tests or anything remotely BDD. I also didn’t get to tackle any client-side magic until the last minute and didn’t make the progress I’d hoped I would.

I like these little projects because I’m getting more comfortable with making decisions on where business logic should go, Rails conventions, getting set up, finding gems to build off of, and a host of other things I had to stop and Google every two minutes during development.

One of the most difficult parts of this project in particular was naming. Throughout this post, I talked about things in terms of attributes, but I couldn’t name my model “attribute” or anything remotely similar because Rails has a monopoly on generic terms like that. I actually had to go to a thesaurus and ended up using “traits” as a drop-in replacement for “attributes” throughout my project. I kept a list of Rails reserved words open in a Chrome tab throughout developement and had to check it several times to prevent the cryptic error messages that are bound to follow that type of mistake.

I’ve posted the code on github (more or less my first project of consequence, so that’s exciting…).