So you joined a startup. You have plenty of stock options, a new company to build and a lot of work ahead of you. What's motivating you is the challenge and the chance to learn and grow. But be honest. You really want your stock options to be worth something one day. You want to
get rich here.
Being a Java developer, you are in the right position. The fact that your company uses this language, possibly even in the Internet/intranet context, will practically guarantee you the attention of investors and the stock market. But it's a long way from early hype to long-term business success. There are a few exceptions, but most companies will need a solid product and many happy customers to have any kind of success. Building a quality product, however, is where the problem begins. Classical approaches to software engineering (SE) do not work in a startup environment, but without SE your product will lack quality.
Classical Software Engineering
Software engineering is the application of engineering principles to the building of software. Classical SE suggests that development takes place in stages: analysis, design, implementation and testing. It defines the techniques and processes used to set up a system of control, testing and approval at every one of these stages. The SE processes require each stage to be completed before the next stage begins, because the output of a stage must first be understood, tested and approved. As you can easily imagine, SE requires some bureaucracy. However, when properly applied, SE holds the key to timely delivery of quality software.
The Startup Difference
Startups face several unique hurdles that must be overcome to ensure success. Therefore, classical SE techniques and principles need to be modified for this special environment:
It is often argued that the deliberate processes of classical SE are not applicable under these conditions. It is my contention that some of the basic SE principles, processes and methods can be utilized successfully, even by startups, to make the company operate more efficiently. As one experienced developer put it, "Engineering is making the right compromises." This is especially true for any startup. By compromising at the right places and modifying SE for this special environment, you can come up with a version of SE that will work for startups, without creating too much bureaucracy.
- Short time to market
- Immature, undefined market
- Fast growth in the number of employees
Understanding the Requirements
In classical SE the life cycle of a software product starts with requirements analysis. The goal is to identify and quantify all customer requirements through close interaction with the customer and market research. It is important to quantify requirements. For example, a requirement could either read "the data packets should not be too big" or it could state that "the data packets should not exceed 500 bytes in size." The first requirement is not quantified; its satisfaction is left to interpretation. The second one is quantifiable and therefore testable. Since all requirements are listed, and each one will later have a test assigned to it, a successful pass of all tests indicates that the development effort has been completed.
In startups, the analysis phase does not proceed in this manner. There are no customers in the beginning from whom you can get feedback. Also, the market is still so new, no one can say what is really needed. How do you identify all customer requirements? You don't. You use your common sense, experience and creativity to come up with an initial set of requirements. Should they be formulated in a quantifiable manner? That depends. You may be more certain about some aspects of your product than others. Unless you have an explicit statement from customers, it doesn't make sense for management or marketing to make up an artificial number that is not based on real-world input. It would be a waste of engineering time and money to try to satisfy artificial targets. List all the requirements you can think of and quantify those that you can. Don't quantify requirements with values that have no basis, although you should list a requirement even if you cannot quantify it. By listing requirements and making sure they are addressed during development, you ensure that no requirements are missed. Later, when you do finally get some customer feedback, you can try to fill in the blanks in the requirement list. Even though this goes against some of the foundations of classical SE, it is one of the compromises you have to make in a startup.
New requirements that have not been addressed in the initial analysis and design will be set aside for the next release of the software whenever possible. Because of the uncertainties that go with developing a brand new product for a brand new market, most of the compromises will be made in the analysis phase of the SE process when you work in a startup company.
Designing a System
Once the requirements have been stated, you can begin to design a system that meets them. Since a startup operates in a new market with potentially new technology, your work is likely to contain a significant research component. A prototype may be developed even during analysis or design. Some assumptions may turn out to be technically infeasible. This may force you to change the requirements and modify the design. The analysis and design stages, so nicely sequential in classical SE, are likely to pass through multiple iterations of the analysis, research and design phases in startups.
The design stage is important for any product in any company, which is especially true in a startup. Markets and requirements change constantly. Hence, your product will need to change a lot over time. In fact, the first version of your software will probably have to be redone after its release. It would be great if you could just rearrange the product at this point rather than rewrite it. To a large extent, this is possible if you design your system out of small, independent objects. Well-designed objects exhibit high cohesion and low coupling.
High cohesion means that the object's data and methods remain focused on one task or functionality. The object is an expert at doing one thing. If you have to modify this object's functionality, the changes should not affect other objects.
Low coupling means that the interfaces between objects are small, few and without side effects (e.g., no global variables). The fewer interfaces an object uses, the fewer dependencies it has. Code changes and re-arrangements affect a smaller portion of the total system. You can therefore make such changes faster and safer.
Such modular design also facilitates the rapid growth of a startup. When interfaces to small objects are well defined, you can easily assign well-bounded tasks to new employees. Also, since smaller modules are less complex, new employees can learn and understand their tasks by focusing on the relevant object. As they work on more and more objects over time, they will develop a broader understanding of the system. They can also be productive while climbing the learning curve. If you have few monolithic modules, however, new employees have to work inside such a module with no clearly defined interfaces between their work and that done by other developers. Not only is this an error-prone environment, it will also increase the communication overhead among employees. Unit-testing or at least a code review is easier with a small module.
Several methodologies are appropriate for high-level design. They usually involve drawing bubbles (objects) connected by arrows (messages) on paper. All of the methodologies are quite effective and help you see the system as a whole. If you are using Java to implement the software, you can use the actual implementation language rather than pseudo code to do your low-level design. Use interfaces for specifying APIs so that classes that implement those APIs can be written later. Object definitions can be specified as abstract classes, which can then be subclassed and filled in with specific implementation details.
Implementation of the design should be one of the smallest tasks in software development. If requirements analysis and design have been done thoroughly, you will simply fill in the blanks during implementation. You should create proper source code documentation, check return values and follow a suitable coding and error-handling standard. Such standards should be defined before implementation ever starts. Java's exceptions provide a good foundation for implementing error-handling, but they do not define a complete error-handling standard.
The error-handling standard determines how user errors, program exceptions (for example, I/O errors) and internal system errors are handled. Setting a standard once will save developers from having to make these decisions again and again, in a possibly inconsistent way.
Standards will make life easier not only for new employees, but also for those who do maintenance. Reviews can be used to test for compliance with the standards.
Testing does not start only when coding is complete. Analysis and design documents can be tested through reviews. In a review, check that all requirements have been addressed. In general, reviews are an important part of testing at all stages. During implementation they can even substitute for more resource-intensive kinds of testing, such as unit testing. Once you have finished coding subcomponents or the whole system, run automated test cases. You can start designing the test cases as early as the analysis stage.
SE techniques are effective only if they are used. Unfortunately, many developers and managers resist SE practices. This is not so much an engineering issue as it is a psychological and organizational one.
Many individuals who are attracted to startups have had bad experiences with the
design-by-committee style of SE practiced in large companies. They come to startups because they don't want to deal with bureaucratic overhead. When you suggest SE practices to these individuals, the answer will often be, "Sure, we need some SE, but I've seen how much overhead it requires. We don't have time for that now...." The practices discussed here, however, don't require much overhead.
These practices do help you build a quality product that is easier to maintain and grow as the company grows and as markets change. Less time will be spent on debugging and fire drills. This is important for everyone who wishes to have a life outside the company. The higher quality of your product and the responsiveness of your company will result in satisfied customers, good press, and higher sales. This will keep everyone motivated, and the value of your stock options will increase. Since money is already a point of motivation, it can be used to convince dubious developers or management.
As an early member of a new company, you have both the opportunity and the obligation to shape its culture. You need to create an environment in which SE is practiced naturally. New employees, immersed in this environment, will adopt SE without even questioning its application. Rather than forcing your point on people, guide them toward seeing that SE can be a powerful solution for the software development problems encountered in startups.
This brief overview of how to use SE in startup companies will be followed in upcoming issues by details on how SE practices make the software development process more efficient in startups.
About the Author
Juergen Brendel is a software architect at Resonate Inc. He welcomes your feedback via e-mail at &127;[email protected]