http://www.perlmonks.org?node_id=788328

Once when I was six years old I saw a magnificent picture in a book, called True Stories from Nature, about the primeval forest. It was a picture of a boa constrictor in the act of swallowing an animal. ... In the book it said: "Boa constrictors swallow their prey whole, without chewing it. After that they are not able to move, and they sleep through the six months that they need for digestion." I pondered deeply, then, over the adventures of the jungle. And after some work with a colored pencil I succeeded in making my first drawing. My Drawing Number One. It looked something like this:
xxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I showed my masterpiece to the grown-ups, and asked them whether the drawing frightened them. But they answered: "Frighten? Why should any one be frightened by a hat?" My drawing was not a picture of a hat. It was a picture of a boa constrictor digesting an elephant. But since the grown-ups were not able to understand it,...

The Little Prince, Chapter 1 by Antoine de Saint-Exupéry

I must be the snake the little prince was thinking of because I seem to be in the habit of swallowing elephants. I often find myself needing to learn a complex system inside and out very quickly. Sometimes, it is because I have a new client. Especially in my early days I would often get invited to lead the design on a half finished project after a series of the big guys (Accenture, etc) had successfully botched the project. Until then, companies don't really look beyond the obvious and safe sources of consultants. More recently, I have either needed to evaluate 3rd party software systems for in-house use or even our own code for refurbishment. And then there are volunteer projects.

Over the course of time I've evolved a strategy for working through complex systems rather quickly. I won't say it isn't a lot of work (it is), but it keeps me from going in endless circles, so that at least the work moves me forward.

I'd be interested in knowing more about how other monks handle going about learning a new system quickly. Not everyone learns the same way. Also if you see any non sequiturs or an obvious omission, I'd appreciate the feedback. Writing something like this up feels a bit like trying to explain how to tie a shoe. It is all to easy to take for granted a crucial step and leave it out. I also have an ulterior motive. pmdevils are also in the position of trying to swallow elephants when they join.

The ten steps can be summarized (they will be explained in more depth later below):

  1. Gather together whatever documentation there is
  2. Experiment with the front end
  3. Study permanent data streams and persistant data
  4. Explore the class/type systems
  5. Understand where the code lives
  6. Scan and categorize the codebase
  7. Study back end CRUD operations
  8. Study front end CRUD operations
  9. Study permissions/security infrastructure
  10. Explore a well defined functional area to see how the system works in a specific case.

This is, of course, an interactive process and it often involves a lot of backtracking as well. Often the first pass through a step results in more questions than answers. Then I go onto another step, and find an answer to something I couldn't figure out in the previous step. If the answer is important enough, I may go back and redo all or part of the previous step.

Although the first step is "gather together documentation", the process describe below will work even if documentation is sketchy and you have to manually go through code and database schemas. Documentation makes the process much easier (if it is correct), but it isn't necessary to the learning process.

Figuring out how much detail to do at any one step of the process is a bit of an art. Usually I try to be as superficial as possible. For each stage I try to learn enough to categorize things in some sensible way that tells a story about data, behavior or the interaction between them. Then I move on to the next step. When the fog to understanding ratio gets out of hand, I backtrack one or two steps and go into more detail until the fog clears.

As I work through the above list I usually keep copious notes and organize them as I go. Writing out my answers to the questions at each step helps me identify unanswered questions. I also find I'm accumulating knowledge much faster than I can absorb it so the notes act as a memory bank, especially if they are well organized. I frequently organize and reorganize the notes as I go. The act of organizing them also helps me remember more. Finally, if the system is poorly documented, the notes become a first cut at improved documentation.

As one skims through the list, the first thing that might stand out is that a third of the steps are data centric, including the first detailed analysis step (study data streams and persistant data). For many programmers starting with data may seem counter intuitive. Programming is about making data do something, and code is where the action is. But data puts an upper bound on what the code can do so it provides a way of focusing attention and understanding the scope of the system. It is also the easiest discreate nameable thing to get a handle on. It acts like the end of a thread used to unravel a ball of knots.

Another thing that might stand out to the OO fans reading the list above is that there is no mention of roles or behaviors or all the other jargon of the OO world. I find that interesting because I've been doing OO since the late 80's and it is virtually impossible for me to design software that is more than 500 lines without ending up having at least a few classes. Even before C++ became popular I was organizing C functions associated with specific data structures into dedicated files and designing dispatch handlers for the data structures. It just seemed like the right way to do things.

I'm guessing the reason for this is that data is a long hand that reaches throughout a system. Or maybe it would be better described as blood and oxygen. Every aspect of the system needs it regardless of its role front end or back end.

Classes and objects are marvelous ways to organize code. They can also be a great way to get a user to cough up requirements. Users often have a hard time talking about data apart from the things they do with the data. However, code and end-user requirement gathering are only two of the many ways a system needs to be categorized, sliced and diced in order to understand it. On the front and we need to understand workflows. On the database we need to understand normalization or we won't really get the benefit of our database's SQL engine. Somewhere in between we need to understand aspects: large swaths of functionality that are content independent.

To fully understand a system it is also important to get a handle on how all of these different ways of categorizing data, code, and end user functionality relate to one another. The learning strategy elaborated below tries to help in that process. Whether it succeeds is for you to decide. But if it seems counter intuitive at least consider trying it the next time you need to learn a system quickly. You might be surprised at the results.

I apologize in advance for the list like nature of this elaboration. Partly I don't have the time to expand it fully right now. Also, I fear turning it into a narrative with examples would likely stretch this node to book length. Hopefully though I will have at least raised some questions and pointed out things to look for that might be helpful for others.

Step 1: Gather together documentation

You may have documentation. You may not. It may be up to date. It may not.

Even out of date documentation or incorrect documentation can be helpful if it gives you a sense of the design philosophy or a road map through the code. My first step is to skim through the documentation and make some sort of assessment of what is there and how much I trust it. However, unless the documentation is amazingly clear and well written, when first learning a system I usually take the documentation with a grain of salt. I like to get down and dirty into the guts of things and see how it all works with my own eyes.

Even when I trust the documentation and it seems relatively complete I still use the remaining steps to as a road map through the documentation and check list for my understanding of the system.

Step 2: Experiment with the front end

From the user's point of view, what does the system do? Do this as a brief survey to get a "feel" for the application or system. The goal for this step is to provide context for the more detailed study of how the system is implemented.

  • What are its main areas of functionality as evidenced by user manuals, help documentation, or help systems.
  • How does the uer access these areas of functionality? Menus? Toolbars? Dedicated widgets? URLs?

    For example, at Perl Monks all functionality is available via specially crafted URLs. However, one doesn't normally access features directly via URLs. Instead one either uses the link lists in the upper corner or one of the several nodelets found in the side bar. The upper right corner has links to the main functional areas (mostly), and the nodelets handle special purpose function areas.

  • What is the work flow like? How does one move from screen to screen or webpage to webpage?
  • Is there obvious security? How does it interact with the user? At login time? At other times?
  • How does it perform? Is it slow? Lightening fast? Something in between?Any obvious reasons?
  • What, if anything, is customizable? How does one do it? How much can an end user change? An administrator? What depends on level or security status?

Step 3: Study permanent data streams and persistant data

  • look for all the places data is stored or streamed
    • databases
    • disk files (data files and configuration files)
    • code segments (see understand where code lives)
    • real-time feeds of data stored/geneated elsewhere
  • understand the structure of each (or lack thereof)
  • how is structure revealed?
    • data dictionary
    • language (data is stored in a linguistic sample and needs to be parsed before extraction)
  • try to cluster the tables and data stores into functional categories (document and explan the role each table plays in these)
  • identify "core" tables that are shared by several different functional areas and seem to transend any particular functional area or topical organization.
  • look for mismatches between data structure and content, i.e. divergences from the assumption that (a) table = kind of thing (b) row = examples of a particular kind of thing (c) field = discrete atomic data.
    • tables storing more than one kind of record: sometimes common data (ids, audit trails) are stored in a master table. All database rows have an entry but their real meat (the attributes that store actual content) are else where in a table that is joined one-to-one
    • fields storing multiple attributes, repeating groups or even entire objects or sets of objects. Sometimes fields can function as mini databases in their own right.
  • keep refining until you feel the categories tell a cohesive story.
  • keep notes of what you've learned along with any unresolved questions

Step 4: Explore the type systems

  • look for all the different ways the system categorizes data and defines relationships between categories. Systems often have more than one of these:
    • type fields on database records - field name often contains things like "type" or "kind". However, any field whose value determines which attribute sets or functionality is applicable, should be considered a type field. These fields aren't always conveniently named type or kind. The initial step of experimenting with the system as an end user should give you some hint of what sort of field to look for. For example, an expert system that searches for case history and legal precedent that can be used in a particular country might have functionality and attribute sets that are dependent on the value of a country's "legal_system_id".
    • code structure - is it divided into classes? How do they inherit from one another? What is driving the division of code into classes? It may not be the same thing as what drives the database record.

      Some systems use classes primarily to organize the system around "aspects" - areas of functionality that can be defined indepenent of content. Content-based type systems are handled based on data. They have no corresponding code classes.

      For example, the Everything engine that runs the Perl Monks website uses classes to organize code into a database backend (inherits from DBI) and a front end request handler (inherits from CGI). It also has an elaborate system for assigning each design element and each node written by the user to a "nodetype". These node types can inherit from each other and they drive both the choice of applicable attributes and the available functionality. However, these node types have no corresponding classes in the code.

  • for each type system diagram (or create an outline) explaining the relationships between the types within the system.
  • explore and document how each type correlates to database tables and is implemented in code. 1-to-1 is often the exception more than the rule.
    • is the type db only or does it have a corresponding code class?
    • one table storing objects belonging to diverse classes (e.g. node table @ PM)
    • multiple tables joined together 1-to-1 for each dbtable row (e.g. a single object table joins with one or more tables containing attributes specific to that object)
    • subsets of records from a cross-reference or detail records (e.g. order object may include order lines, but db puts orders and order lines into separate tables for normalization reasons.)
    • classes may store a private copy of data at the other end of a foreign key for convenience.

      Note: this is almost always a bug waiting to happen unless the duplicated data is immutable when the code was written and always will be from now until eternity. Or alternatively the object is very transient (e.g. one report run or edit transaction).

      It is *very* hard to keep that data in sync with the master copy. The code to do it often gets the edge cases wrong, creating subtle bugs. Also even if green field development got it right to start with, maintainers forget about this sort of denormalized data and usually fail to find all the places affected by a database change.)

  • explore how each of the type system interact with the other, if they do.
  • keep notes of what you've learned along with any unresolved questions

Step 5: Get to know where the code lives and how it is processed

  • places to look for code
    • disk files
    • database rows - which ones? which tables/record types? which fields?
    • embedded in fields containing non-code data
    • configuration files
  • how is it processed?
    • what compilers/interpreters are used?
    • is it filtered in any way before processing?v
    • what restrictions are there on normal syntax?
    • how are modules and libraries included in code stored in the database? Can any module be used? If so, how is the module or library installed in the system so that it knows where to find it?
  • with a better idea of where the code lives, you may want to go back and redo steps two and three looking for additional sources of data and/or type systems.
  • keep notes of what you've learned along with any unresolved questions

Step 6: Scan and categorize the codebase

If you are lucky a certain amount of categorization may have been done for you. If not, the only way to do this is to look at each file! Here are some things I do to speed up the process:

  • make a preliminary categorization based on file name. If the name is especially obscure, one might also very briefly skim the file to see what it is about.

    Do not expect to get things right at this stage. Some files will be miscategorized.

    When categorizing focus on (a) files that belong to a specific aspect, e.g. retrieval of persistant data, security management, caching/performance, XML generation, HTML generation, generation of format XYZ, HTTP get request processing, customization management, mail interface, code to handle specific content areas, and so on.

  • Try to explain how the categories fit together to create the system you saw in step 1. Are there any area of functionality that seem to be missing supporting code? if so review the code categoriation again. If one still can't see where the code that does X is coming from, keep notes.
  • Pickthe code in one category (preferably something simple) and study it in depth to get a sense of coding style, architectural style and documentation level.
    • what are the entry points to this area of functionality used by code outside of this functional area? If you had to write a public API what would it look like?
    • what precisely are their parameters and return values? what happens when illegal values are passed? what counts as illegal values? read the code to figure this out if the documentation is insuficient.
    • is the code easy to read? dense but well written? a mess? is there a consistant style? How would you describe it?
    • how is data used? how is code grouped into subroutines?
    • how good is the documentation? does it match the code?
    • how well organized is the code? Is hardcoded data isolated and easy to change or scattered about? Is functionality broken down into sensible chunks? Are functions well named and self-documenting? Is data?
  • keep notes of what you've learned along with any unresolved questions

Step 7: Study backend CRUD operations

  • How does the code creates, updates, deletes, and displays persistant data? Is it treated as an aspect with a generic engine? Is it left up to each class? A hybrid?
  • If there is a generic portion, identify all the code units that belong to it. If this is hard to do, go back to the previous step and review the code more carefully.
    • Grepping for key words associated with database processing may help. For example, if the codebase is written in Perl, one would want to look for modules that use modules named 'DBI::', 'DBIx::' or 'DBD::'. Alternatively one could look for strings like 'sql' or even for specific database table or field names, especially if those fields come from "core" tables that aren't content specific.
    • If code units are stored in the database, there may be a code search facility. Ask others more familiar with the system if there is such a thing and how to use it.
    • once you have found a few starting modules you can either look at the modules they include or look for consumer modules. Sometimes these modules belong to other subsystems but sometimes they don't.
    • the names of modules can also be a guide to finding other modules in the same subsystem. See if there are patterns in the way database associated modules are named and then look for other files that have similar naming patterns.
  • Study the generic database code in depth.
    • what are the entry points to this area of functionality used by code outside of this functional area? If you had to write a public API what would it look like?
    • what precisely are their parameters and return values? what happens when illegal values are passed? what counts as illegal values? read the code to figure this out if the documentation is insuficient.
  • Figure out how content-specific classes and type hierarchies use the database. One way to do this is to pick two or three types from each of the content related type heirarchies. Choose types and classes whose names are somewhat original. Searching code for a type named 'code' or 'HTML' or 'object' is likely to lead to a lot of false hits.
    • take advantage of built-in systems for tracking data-code associations wherever possible: some systems use naming conventions or provide an infrastructure to track the associations between code and data structures or classes. For example, the Everything Engine used by Perl Monks has a page (visible to pmdev's only) that displays the database tables used by each node type along with all of the code units involved in validating data or generating HTML for pages that edit or display data from those tables.
    • use grep and code search tools: look for the name of the type you are researching or the name of one of its superclasses if nothing is found. Even in system that track code-data relationships, there can be important information elsewhere in the system, especially in code units that contain subroutines called by the code units that are explicitly tracked.
    • for each code unit found, study the input parameters, output parameters and internal code calls. What information must be passed to retrieve or edit data? What gets sent back? Does the code call the generic engine subroutines? go directly to the database? call other subroutines?
    • If it calls other subroutines, look up those subroutines and ask the same questions. Repeat this proces until you know exactly how data moves from the front end to the persistance engine and back again.
  • how is security and user permissions enforced in the backend? is it handled in code? in the database? some combination of the two?
  • keep notes of what you've learned along with any unresolved questions

Step 8: Study front end CRUD operations

Taking the same types as before, study how those types are displayed to the user.

  • can the user choose from a variety of ways to present the data: XML, PDF, a pretty browser page, other? If so, what are the display options available? Do they vary depending on type? Using which type system? Do they vary based on the user's security status? what other factors affect the views of data available to the user?
  • how does the user request the system to display a particular view?
    • click on a link? If so, what is the URL syntax of that link. When the system recieves an HTTP request, how does it process that URL?
    • choose a menu option? If so, what event driven API is being used to process menu choices? What are the capabilities of that API? Which events are being used to handle the request?
    • other?
  • what are the possible display types for the system?
  • how do the display types relate to CRUD operations? are there several differnt views for each operation?
  • how is each displaytype processed? Do any display types have generic handlers? If so, what code is involved in the generic handling process? Is there a way to customize the generic process for specific classes? Or is everything processed the same way?
  • for display types without generic handlers (or with customization of generic handlers), where does the type-specific code live? how is it triggered? How is it structured?
  • where does the look and feel of the front end come from? What data drives it? what code?
  • How is information about permissions used in the front end? Are certain user interface elements disabled based on permissions?
  • keep notes of what you've learned along with any unresolved questions

Step 9: Study permissions/security infrastructure

  • Where is permisison information stored? In the database? In code? In disk files? Other?
  • Are security checks centralized in one place? Or is security logic scattered about the codebase and various databae fields? If centralized, find all the code related to security and analyze it.
  • How do the front end and back end of the database work together to enforce security? If a user without permission somehow manages to trigger the front end code without a proper user interface, e.g. by sending a properly formatted URL, what happens?
  • keep notes of what you've learned along with any unresolved questions

Step 10: Study a well defined data collection/functional area

  • identify features visible from the front end
  • study the functional area until you can account for all behavior visible from the front end:
    • identify all data used by the functional area (see step 3)
    • identify all classes used by the functional area (see step 4)
    • identify and trace through all code used by the functional area (see steps 5-8 for tips)
    • reexamine all code for security and permissions management (step 9)
    • repeat or backtrack above steps until all functionality is explained.
  • assess code organization and quality
    • does coding style and quality match that found in <a href="#step6>step 6?
    • is the data that drives the look and feel of this code segment centralized? If not where are all the pieces found? Can you construct a data structure that would store all the information in one place? how much would the code have to change to use such a data structure?
    • is security data centralized? If not, where is it located?
  • assess extensibility: if you wanted to subclass the entire functional area and add custom look and feel or functionality, what would be involved?
    • could the system support two custom instances side by side? Or is this functional area singleton? do all customizations affect the one and only copy?
    • what would one need to do to extend the functional area? Are these extensions supported by the system? would you need to create additional database tables or fields? add new database records? modify existing code? add new code units?
    • if data or security is decentralied, how will you deal with it? can you design the subclass so that it is more centralized? Or is that impossible without great disruption of the code?
  • assess performance: How is the performance of this area? What looks like it might cause problems based on past experience with other systems or similar designs and technology?
  • keep notes of what you've learned along with any unresolved questions

Nuf said.

Best, beth

Replies are listed 'Best First'.
Re: Swallowing an elephant in 10 easy steps
by fullermd (Priest) on Aug 14, 2009 at 03:08 UTC

    As one skims through the list, the first thing that might stand out is that a third of the steps are data centric, including the first detailed analysis step (study data streams and persistant data). For many programmers starting with data may seem counter intuitive. Programming is about making data do something, and code is where the action is.

    On the contrary, this is exactly how I approach things.

    After all, data is where the action is; code is just transforming one set of data into another. The data you start with and the data you want to end up with are what determines what code you need. And, a data model (not necessarily the data model you encode into your database or file format or whatever) is a proxy for the customer needs as well.

    The first question I ask (of myself, if not necessarily of other people) on any project is "what data are we dealing with?" You can't figure out what the code needs to do until you know how the data will be organized, and you can't figure out how to organize the data until you know what data you have. Of course, you can't figure out how your data can best be organized until you know what you'll do with it to, so it's totally a back-and-forth process between data and process, but understanding of both preceeds code.

    Everybody Knows that you need both data and process understanding to figure out how to organize everything, and that they each impact the other, so you have to get both together and let them hammer out the necessary compromises. But, IMO, any given person thinks of one or the other first, and then applies the other to it.

    I feel like this is one of those dichotomies by which you can classify types of programmers. Not that it reveals anything vital by the classification, but at least it helps you communicate across the gap by realizing it's there. And it doesn't mean that you necessarily think your primary grabbing point is the more important. I'm very much a data guy, but I'm well aware that the processes are vital things to understand to build the data model. I just start with the data itself.

      After all, data is where the action is.
      As the famous quote goes:
      The programmer at wit's end for lack of space can often do best by disentangling himself from his code, rearing back, and contemplating his data. Representation is the essence of programming.
      from The Mythical Man-Month.

      After all, data is where the action is.

      As the famous quote goes:

      Show me your code and conceal your data structures, and I shall continue to be mystified. Show me your data structures, and I won’t usually need your code; it’ll be obvious.
      from The Cathedral and the Bazaar.

Re: Swallowing an elephant in 10 easy steps
by jdporter (Paladin) on Aug 13, 2009 at 18:00 UTC

    Why not just assign ten people to the task, one step per person?

    oh, wait...

    Nevermind. :-)

Re: Swallowing an elephant in 10 easy steps
by biohisham (Priest) on Aug 13, 2009 at 17:18 UTC
    And this caught me wondering about the time constraints, how long can it take to walk along these 10 steps?I know this is more of a general question, but what I mean is, the average of the time taken from you while setting to work on say ...about 5 projects where you had to involve this strategy...


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.

      The time drivers are the overall quality of the design, ease of access to code and database schemas, and the size of the system: the number of database tables, the complexity of the type/class system(s), the amount of code, and the number of features in whatever subsystem you explore in step 10. Rather than an average, I'll take the most recent example, Perl Monks.

      The Perl Monks website has 83 data tables, two main type hierarchies (nodetypes and perl classes), a core engine of about 12K and about 600 additional code units spread throughout the database. Documentation is scattered and mostly out of date. The initial architecture seems solid but its features have been used inconsistently over time. Accessing the schema and code samples is slow because there is no tarball to download - it has to be done through the web interface or manually cut and pasted into files off line. The database/class assessment (1-4) took about 16 hours. Steps 5-7 took about 30 hours. Steps 8-10 took about 24 hours. All told that is 70 hours, including writing up documentation and formatting it with HTML.

      However, I always like to leave myself some breathing space. If I were contracting to learn a system that size, I'd want 90 hours and an opportunity to reassess time schedules after the initial code walk through was complete. If a system is very poorly designed this process takes somewhat longer.

      A crucial element in controlling time is controlling the amount of detail needed to gain understanding. It is easy to lose sight of the forest for the trees. That is why I advise stopping and moving onto the next phase once your categories give a place to most design elements and the categories work together to tell story. That is also why I recommend backtracking as needed. Sometimes we make mistakes about which details really matter and which can be temporarily blackboxed. Knowing I can backtrack lets me err on the side of black boxing.

      The other element affecting time is, of course, the skill of the analyst or developer. I have the advantage that I have worked both at the coding and the architecture level of software. I doubt I could work that fast if I didn't know how to read code fluently and trace the flow of data through code. Having been exposed to many different system designs over the years also helps - architectural strategies leave telltale footprints and experience helps me pick up on those quickly.

      However one can also learn these skills by doing. The more you practice scanning, categorizing and tracing through code and data the better you get at it. It will take longer, but the steps are designed to build on themselves and are, in a way, self-teaching. That is why you can't just do the 10 steps in parallel as jdporter jokingly suggests below.

      However some theoretical context and a naturally open mind definitely helps: if you think that database tables should always have a one-to-one relationship with classes you will be very very confused by a system where that isn't true. If I had to delegate this work to someone else I probably would work up a set of reading materials on different design strategies that have been used in the past 30 years. Alternatively or in addition, I might pair an analyst with a programmer so that they could learn from each other (with neither having priority!)

      Best, beth

      Update: expanded description of the PerlMonks system so that it addresses all of the time drivers mentioned in the first paragaph.

      Update: fixed miscalculation of time

        I haven't see the PerlMonks code, but I have seen the perl source and read much of the documentation. I wonder if you have studied it, how you would tackle it and what reasonable time line expectations might be for gaining an overall understanding of it.

Re: Swallowing an elephant in 10 easy steps
by MadraghRua (Vicar) on Aug 14, 2009 at 19:35 UTC
    Nice post. I use a variation on this figuring out how to develop, assume control of or modify apps for scientists. Just out of curiosity, how much time do you spend talking to people? from your writing that is the one difference I would have with you - I usually find documentation to be sketchy at best. When I've done these types of projects I usually try to make time to talk to the developers, the dbas, IT support, the end users. Sometimes you can eliminate a lot of work with a couple of questions. And I've also found some of my interpretations based on analyzing code base were wrong - I corrected this by again looking at the data flow and asking the developers & users what was going on in that portion of the application. Of course if you're taking over a botched project or a closed app, most of this conversation is with the end users and IT support for the system.

    MadraghRua
    yet another biologist hacking perl....

      The amount of time spent talking with/listening to people varies with the project and the availability of people. I tend to have two very different kinds of conversations: (a) requirement oriented conversations focused on goals and priorities (b) deeply technical conversations focused on understanding the system and finding the least disruptive way to meet those goals.

      Getting a sense of goals and priorities before one starts such a large analysis project is an absolute must! Even if I and my team are the end users, it is still a good idea to explicitly clarify our goals and expectations one to another. When we share a work environment and culture it is all too easy to make assumptions.

      The goal setting conversations can strongly affect the choices made during the formal technical analysis. The process described above gives one an overview. I generally know what data there is and how it flows, but I have only studied a few of the subsystems in depth. Having a sense of goals is especially helpful in step 10, where I choose a subsystem (and sometimes more than one) to focus in on. In earlier phases knowing goals helps me keep an eye out for (a) hidden resources in both code and data that could support goals but aren't being used (b) missing resources that must be added. (c) possible bugs or extension difficulties in existing features. I usually try to keep notes as I go.

      Requirements conversations tend to happen primarily before even beginning the process and then again at the end, when "what next" decisions need to be made. They can also happen midway, if the analysis process seems to be taking more time than originally expected. I always like to give people a chance to reevaluate priorities. I'm more likely to get paid for my time if the client is the one calculating the trade-off between goals, time, and money.

      Deep technical conversations tend to happen during the process described above. First, in some cases there are no people. If I'm reviewing an open source package for its range of features and customization support, documentation, code, and database schemas are all I have to go on. If it is poor or sketchy then the process takes longer because I have to reconstruct more.

      Even when there are people, I need to keep in mind two important constraints: Many people, including technical people, are much better at doing their job than explaining it. Even if they are good at explaining, they have limited time to assist in the more detailed phases of analysis. The more I can get on my own, the happier they are.

      During step 1, the initial documentation phase, I look for "oral documentation" and try to assess the level of team knowledge about their own system. Knowledge of one's own system can deteriorate over time. In a complex system, most people are only asked to work on a small part of it. Team culture may not encourage them to look outside of their own box. It may be easier to hard code data in a function than go through the bureaucracy involved in adding a new field to a database table. This eventually results in patches and enhancements that don't quite fit with the original design and even the original authors of the system may no longer fully understand how the system works. But when the oral documentation is good, that is wonderful and it can indeed save hours of time.

      I also like to understand how the development and maintenance teams function. Is there an overall philosophy? Has it changed over time? Do they have a formal structure to enforce that philosophy? Or do they rely on organic methods? Does it work? Why or why not? Do they read their own documentation? If not, why? When they do, does it help? What would make it more helpful? This kind of information gives me context when I see a design with two competing architectures for the same aspect (e.g. two different permissions management infrastructure).

      At the end of each step, I ask the existing team to review my work. This helps catch misunderstandings, especially in the earlier steps where I haven't yet connected up the code and data. I'm constantly trying to control the level of detail and sometimes I make incorrect snap judgments based on the way things are named. If that can be caught early on by an experienced team member, so much the better. As you have said, understanding data flow is a crucial tool in correcting mistakes. How data is used is just as important as what it is called and how it is arranged (though sometimes these are in conflict). In the early stages, data flow knowledge isn't there yet, though sometimes I will try a quick grep through the code to see if it sheds any light on an oddly named field.

      While going through each step, I keep a list of unresolved questions. I pick the most important questions and ask the existing team how they might answer them. I find that people seem to find it much easier to talk about how a system works when they are asked about a specific part of it. Even design philosophy discussions tend to be more informative and exact if I can point to two specific examples that challenge the assumption of a single philosophy.

      Best, beth

Re: Swallowing an elephant in 10 easy steps
by biohisham (Priest) on Aug 14, 2009 at 21:06 UTC
    Over the past few hours, I have been trying to identify with these 10 steps. The suggestions and ideas you graciously shared are reflection-inducing. Starting off, these ten steps are like beads to a string, I had the notion that this is so much of a teaching-material quality, because you have addressed two interleaving concepts, the Database issue and the Programming one. So seriously consider having this published and displayed on a wider scale to those whose interests fall inside these concerns. I mean after having duly taken into accounts the many suggestions and inspirations that would pour.

    within the points 3-6, the area where scanning, categorizing and tracing is more crucial, Exploring the type system can by far be one of the toughest takes especially while exploring the code structure and the classes relationship on one hand and on the other if a database is involved, the records types. The flow between classes and the events that trigger these classes, the associated variables and scopes are all places where an attention has to be sharp, refined, present, so without a clear understanding of the data streams and the way things go, and how these data travel through classes and code back and forth with the combined ability to visualize them in that act, a correlation between these two steps can be illusive.

    As I said I have been trying to identify with these gems, It appears to me that you have a programming style that is -if I may say- based on characterization, for something to be cognizable enough it has to have this character to it serving as a dimension with every involved character behavior pretty much as in a story, interleaving, associating, working together... but I am failing to reach to figure how I can read the plot from the code and where the main knot of it is.

    With regard to the time constraints, you have dealt with fairness at addressing the time requirements and the spaces while bearing in mind the iterative nature of the process. That is an admiration of skills I have for you, I look up to this level of stability. :).. Thanks for sharing this with us...


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.
      but I am failing to reach to figure how I can read the plot from the code and where the main knot of it is.

      The metaphor of story may not work for everyone. If I were to deconstruct the concept of story, I would point to two key features of well-written stories:

      • Every detail of the story has a place. There is nothing superfluous. Everything plays a role in developing either the plot or the characters or the fundamental message (a.k.a. theme) of the story.
      • It is possible to step back from the story and construct a narrative to explain the role of each detail in the story.

      A good choice of categories for database tables lets us assign a role to each table. Once we have a set of roles we can try to construct a narrative to explain how each of those roles works together to create a whole system. The question is: have we created a well-written story?

      In particular, our narrative needs to explain how the categories we've chosen give the front end the data it needs. We also need to explain what functionality could explain the data that has no obvious connection to the front end and how it may related to the goals of the end-user view of the system. Maybe it helps performance? Supports development? Represents related, but unused features? Solves an architectural problem related to system design? Sometimes it is obvious what kind of functionality this extra information might support. If it isn't, we can put them aside for a bit and hope that maybe their purpose will be clearer when we see whether or not the code uses these tables, and if so how.

      However, if we find more than a few things we can't categorize or our categories don't seem to fit together, then we also need to take a hard look at the way we are categorizing.

      According to psychologists who specialize in memory and cognition, experts and non-experts differ significantly in the way they use categories to organize information:

      • experts organize information using more categories than non-experts
      • these categories tend to reflect deeper principles rather than superficial features.
      • these categories are cross referenced to each other in ways that make it very fast for experts to retrieve information and apply it to new problems in their area of expertise.

      For example, a novice might try to group database tables based on structural features like primary key or the presence of blob fields. However, she is likely to find it very difficult to use these categories construct a narrative explaining what she saw on the front end because the categories are too superficial. Since she can't compose a narrative, she has to rethink her categories. If she is lucky, trying to construct the narrative to explain how the data supports the front end might hint at another more meaningful way of categorizing tables. If not, a smart novice will find someone with more experience and ask them how they might organize the tables. Sometimes we do need to learn by watching the example of others. If there are no handy experts, she might try one of the approaches here or here to get her creative juices going.

      The goal of the emphasis on story is to help one question one's categories until they are deep enough to be useful. The iteration and interleaving of code and data and focus on flow are also meant to help enrich the connections between categories and make it easier to retrieve information when you need it. A nice summary of the role schemas (categorization systems/stories) play in expert knowledge can be found here.

      Here also some links to research on expert knowledge for software programming and development. I found a few interesting observations here and there about the role of data and code but none of these seemed to say much about learning systems whole.

      • Expert Programming Knowledge: a Schema-Based Approach - dense review of research literature, 2007. One conclusion was that research results may depend on what language the programmer was used to programming in. COBOL programmers apparently found it easier to understand data relationships than Fortran programmers.
      • Roles of Variables in Teaching suggests that experts cluster a lot of tacit knowledge around the various roles variables play in programs. Teaching that explicitly may help students learn to build better programs.
      • Applying Cognitive Load Theory to Computer Science Education has a few speculative comments towards the end about the role schemas might play in reducing cognitive load. Apparently there isn't a lot of research on how schemas can reduce information overload in programming.

      Best, beth

      Update:in process, to be added: links to articles on expert schema research specifically in the field of computer programming added.

      Update: revised research links to describe information in each article relevant to understanding systems and data/code relationships.

      Update: added links to monkish brainstorming of what to do when you are really stuck trying to understand something.

      Update: clarified the deconstruction of "story".