25 Other Things that BAs Should Know
Most of the recommendations presented here are based on experience, and are heavily laden with opinion. Don’t take what is said here as gospel, but at the same time, don’t discard what is said here without consideration if your opinion differs. We welcome discussion on any of the issues presented here. The recommendations appear in italics.
This book covers requirements gathering and documentation, and to an extent, requirements tracking. However, to be an excellent practitioner of this art, it would be most helpful to have some additional domain-specific knowledge. Requirements engineering is a very broad field. The concept applies not only to software engineering, but to all other forms of engineering, and to most forms of businesses. For instance, if we asked you to set up a food establishment for us, as after successful completion of this course, you’d be better at it than someone off the street, because you’ll have a better idea of what sort of questions to ask. But, back to software engineering: The following is a list of some things that would be very helpful to know before visiting with your first customer or stakeholder.
25.1. Language Classes
Likely you already know that there are a lot of programming languages. But also as likely is that you don’t know that there are classes of languages. Below, we outline the more common language classes.
25.1.1. Shells
Shells are system-level command programs where you issue commands to run programs. This category includes Windows .BAT and PowerShell files, Unix/Linux shells (such as the Bourne Shell, sh, the Bourne Again Shell, bash, the C Shell, csh, and the Korn Shell, ksh), and IBM’s mainframe control languages, CL (Control Language), JCL (Job Control Language), and TSO (Time Sharing Option).
25.1.2. Programmable Shells
Shells with some programming capability, such as a form of conditional command, such as IF and some sort of looping command, such as FOR. Most modern shells are actually in this category. When using shells, use programmable shells, and make sure to check for error conditions at each stage of the processing. It’s a good idea to include the checking of return codes (the success/failure codes that programs generate) as a “non-functional requirement” in requirements documents. This requires that all programs should return meaningful return codes.
25.1.3. In-betweeners
This category includes shell languages that are so programmable as to seem more like programming languages, and programming languages that are often used to start other programs. If efficiency is an issue, and it often is, even if you don’t plan it that way, plan on using a compiled language.
25.1.4. JavaScript
JavaScript is the preeminent language used to program front-end web pages. JavaScript can also be executed at the back end. When used at the back end, it’s often called NodeJS. There are pros and cons of using JavaScript at the back end. JavaScript is not as efficient as some other languages, but using it at the back end means one less language that the staff need to know. Recommendations: Use JavaScript at the front end, but not where HTML in combination with CSS can’t do the job. When scalability is an issue, JavaScript should be used to enhance client-side validity checking, and there should always be “nonfunctional requirements” that validity is checked on the client side and again on the server side. Checking on the client side allows real-time visibility on whether any Submit button can be clicked, and prevents transmission of HTTP transactions that are going to be rejected (and thus also preventing the overhead of sending a rejection page), and server-side checking prevents outside hacking or bad data slipping through when a browser is set to ignore JavaScript.
There are some add-on languages to JavaScript. These include TypeScript, which enforces types of JavaScript, and “front-end frameworks”, such as Angular and React (usually paired with Redux), or a subroutine package such as JQuery.
25.1.5. Loose versus Tight Languages
Loose languages allow item type to be changed at run time. Tight languages do not, and thus provide more checking capability. Using loose languages will get you running faster, so are nice for prototypes, but tight languages will decrease your overall costs.
25.1.6. SQLs
SQL stands for Structured Query Language. It’s an ANSI (American National Standards Institute) standard for querying from and setting up Relational Data Base Management Systems (RDBMSs). SQL is generally conceptually divided into the Data Manipulation Language (DML), which does the creation, reading, updating and deleting (CRUD) of records, and the Data Definition Language (DML), which sets up and modifies tables and the relationships between those tables.
Here are some other things you need to know:
25.1.6.1. Brands & Loyalties
You will find that some people have brand loyalty. Don’t argue with them. Others do not. For those without brand loyalty, if they have an SQL in use already, stick with it. If not: SQL Server is typically the fastest at ad hoc SQL. Oracle typically stores data in the most compact form. DB/2 is typically the fastest at stored queries. MySQL, PostgreSQL, and the like are free.
25.1.6.2. Tables
Data is stored in tables, in rows and columns. There are zero or more rows that come and go, but one or more columns, which are relatively static for a table.
25.1.6.3. Queries
A query (SELECT command) is how we get data from tables, as is, or processed/correlated in some manner. Queries may be stored in the database as views. It’s better (faster and less error-prone) to use a stored view than to send a query from your program.
25.1.6.4. Joins
Joins are how programs link the data from two or more tables together (or in some cases, how they link data from multiple corresponding parts of the same table). These are the main join types:
Inner Join: A join from table A to table B in which only matched rows are used.
Left Join: A join from table A to table B in which the rows from table A are used even if no corresponding B row is present. (A Right Join does the opposite.)
Outer Join: A join from table A to table B in which the rows from tables A and B are used, even if no corresponding B or A row is present (so long as there is a row from table A or table B).
Exception Join: A join from table A to table B in which the rows from table A are used, except where there is a matching row in table B.
25.1.6.5. Indices
An index is a way to vastly speed up reading at the cost of slower writes and more storage. Indices (or indexes) can be regular or enforce uniqueness. Proper index design is the key to fast execution in SQL systems. A missing index will cost execution time, as will an unused index.
25.1.6.6. Insert, Update, and Delete
These commands add rows, change values within rows, and delete rows, each affecting zero or more rows, depending on conditions.
25.1.6.7. Stored Procedures
Stored procedures are SQL programs stored on the database server. Whenever possible, move logic involving multiple SQL commands into a stored procedure.
25.1.6.8. Types
Within a program, data will have a type. Not all SQLs have all of these types, and more types are possible.
Boolean: Stores true/false values. In SQLs that don’t have Booleans, use the CHAR(1) type with a value of ‘Y’ or ‘N’.
Numbers: The NUMBER type can be integers, decimals, or floating point numbers. Decimal numbers are stored as true decimal numbers, but floating point numbers may be stored by some servers as decimal numbers, and by some as binary floating-point numbers. Some servers give you a choice of the floating point format used.
Strings: Strings can be fixed width, variable width with a maximum length, or of
unlimited size (but slow performance).
Dates and times: The DATE type specifies a day; the DATETIME type stores time to the second, and the TIMESTAMP type specifies a microsecond. In Oracle, the DATE type is actually a DATETIME.
Selectors: A selector is a column that specifies a value in another table, usually actually stored as a numeric type (but sometimes CHAR) with a FOREIGN KEY constraint.
Nulls: The “no value” value. Nulls are not equal to anything, even to the extent that NULL is effectively not equal to NULL.
25.1.6.9. Normalization
Database designers sometimes get into trouble with unnormalized or denormalized databases. (But sometimes, they need to violate the following rules for speed.)
1:1 relationships: Don’t store two kinds of things in one table, and don’t store one kind of thing in two tables.
Move common data: If the same kind of multi-part data is stored in two or more places, consider moving that data to a table specifically for it.
Don’t store derivable data: Don’t store data you can figure out, unless it takes too long to figure it out.
Requirements advice: It’s ok to list normalization as a “nonfunctional requirement”, but only if people are given an out. Sheldon suggests “The database(s) used are to remain normalized at all times, except in such instances as are required for speed, and only when the reasoning for such instances are called out in the design documentation or comments. This rule does not apply to scratch tables, intermediate result tables, or reporting-only tables.”
25.1.6.10. Constraints
The database can do run-time checking to protect itself from bad data. Take advantage of every opportunity to add constraints. They take a little time, but protect the data from bugs and in some cases from malicious action. Constraints also serve as documentation on how the data all fits together.
NOT NULL: This constraint prevents a column’s value from being NULL in a row.
CHECK: A CHECK constraint states a fact that must be true of each row, as a formula.
UNIQUE: The UNIQUE constraint states that the value in this column or these columns must be unique within the table.
PRIMARY KEY: The PRIMARY KEY constraint states that this value for this column or these columns are both UNIQUE and NOT NULL. This constraint is also required in order to use a FOREIGN KEY constraint (below).
FOREIGN KEY: The FOREIGN KEY constraint states that this column (or these columns) must (if not null) refer to the primary key of a given table. This constraint can also be used to define what happens when a deletion or change is made to the record in the referenced table, with the choices being (a) don’t allow a referenced record to be deleted or have its Primary Key changed, (b) if the referenced record is deleted, delete the record(s) that reference it, and of the Primary Key is changed, change the record(s) that reference it so that they continue to reference it, or (c) if the referenced record is deleted or its Primary Key is changed, change the reference(s) in any referencing record(s) to NULL.
Requirements advice: Consider a “nonfunctional requirement” that states that any relational database should be protected by database constraints to the extent feasible.
25.1.6.11. Program Interfaces
How people and programs interface to SQL:
Command line: You can type commands (called “queries” even when they’re not really asking anything) at SQL databases. These queries” are useful for creating the database and for producing ad hoc reports.
ODBC, JDBC, and manufacturer-specific: The programs communicate with the database via subroutine calls. This is the most common interface.
C*Plus, Cobol*Plus, and the like: A means used by Oracle and IBM in which SQL is embedded directly into the calling program, without subroutine call syntax, also called EXEC SQL. This can be a big time-saver, as it allows compile-time SQL checking.
Stored procedures and views: As mentioned above, move SQL logic to the database server whenever possible.
25.1.7. Compiled Languages versus Not
Some languages compile to native code. Some compile to pseudocodes (such as Java and .Net), and others are interpreted. Native code gives the fastest execution, but self-cleaning pseudocoded languages are easier to write in. For most business applications, self-cleaning languages are the most cost-effective, but when you need the fastest possible execution, native code is the way to go.
25.1.8. Object Orientation
Object-oriented programming (OOP) is a style of programming in which classes of data are assigned behaviors, as opposed to procedural programming, in which things are done to data. Each can do everything the other does.
Inheritance: In object oriented programming, one class of objects can be built on another, inheriting its data and behaviors, but overriding some. This forms “class hierarchies”, which are sometimes part of the requirements documentation. Such class design (and even whether to use object orientation or to use procedural programming) belongs in the design documentation, and not in the requirements.
25.1.9. Importance of Interfaces
Many things are called “interfaces”…
User interfaces: The user interface (UI) or GUI (Graphical User Interface) is the form the user interface takes. This might be a windowed interface, something entirely graphical, such as a game, the ol’ 24×80 green screen, or something embedded, such as a steering wheel and pedals.
Internal program interfaces: Internal application program interfaces (APIs) are the interfaces between components of a system. If components of the system are to be built by two or more teams, then the entirety of the API had better be a part of the requirements document, but this part of the documentation is usually written by a system engineer, rather than a requirements gatherer or documentor.
Storage: Programs will read and write data to and from external storage, such as disk files or SQL data. If data is to be shared by components produced by two or more teams, then the entirety of the data structure has better be a part of the requirements document, but again, this part of the documentation is usually written by a system engineer, rather than a requirements gatherer or documentor.
Things called “interfaces” in object-oriented languages: In object-oriented languages, an “interface” is a definition of a set of methods (procedures and function calls) that a class promises to implement.
25.1.10. Importance of Sameness
This section is pure recommendation: You need to implement consistency in these areas:
User interfaces: Consistency of user interface is important to the learning curve of the user. Maintain consistency, except where you need to deviate. The best book on this, regardless of your platform, is Inside the Mac, Volume 1.
Coding style: Consistent coding style makes the program easier to understand, and thus cheaper to test and maintain. Coding standards should be in place for a project, but should be at the level of suggestion, rather than requirement. Coding style guides that are absolute rules tend to be more frustration than they’re worth. Sheldon’s style suggestions: (a) “{” goes on the same line as the command it’s part of, (b) don’t put spaces around the operator with the highest precedence on the line (for instance “a + b*c”), and (c) never place more than one statement on a line.
Language class: At any given tier (as in client, web server, or database), there should be one language in use, or at least all languages should be of the same class. For instance, using C# and Visual Basic.Net together works well. PL/1 and Cobol do. C# and C++ don’t.
25.1.11. Frameworks and Inversion
Inversion is where we take control outside of a program, and move it to some outer, containing framework. Sheldon’s advice: A little of this, such as you find in redirection in Unix and data definition in JCL is helpful. Too much, and your program becomes unfollowable. Spring, Spring Boot, and .Net MVC can fall on either side of this line, depending on how they’re used.
25.1.12. Aspects
There is something called aspect-oriented programming, in which you divide classes into aspects. Each aspect does a different type of thing. Sheldon’s advice: 100% of the time, this is a waste of time and effort.
25.2. Tiers
Programs are often divided up into two or more of the following tiers, which typically run on separate computers: Database, Business, Web service, Presentation, and Client.
25.3. Solution-Oriented Architecture (SOA)
Various servers handle different parts of the problem. Sheldon’s advice: This is a good idea if two separate companies are involved. This is a bad idea if not.
25.4. EMail
Servers can send and receive eMail and texts. EMail becomes insecure the moment it leaves the building. EMail is secure if both users are on the same server. Requirements tie-in: Know what was to be secure and when. When in doubt, require that it be secure.
25.5. Web Languages
There are a number of languages used in constructing a web site:
HTML to hold the structure and content at the client (browser) tier.
CSS to hold the styling controls at the client tier.
JavaScript to control programmability and behavior at the client tier (and possibly add-ons, as discussed above).
JSON or XML (including the SOAP variant) to hold data as it moves between JavaScript control and the server tier.
Back-end languages (hundreds of them) to control what happens at the server tier and above.
25.6. Ways
There are a lot of ways to get things done: (Sheldon’s rule: Any time you want to do something, there are a thousand ways to do it wrong and a hundred ways to do it right.)
25.6.1. SQL or Not
SQL and NoSQL are not the only way to store data. Consider also indexed sequential (ISAM) files, random-access/direct access files, and sequential files.
Data that is tabular in nature (data which can easily be stored in tables) can be most efficiently stored and retrieved using either SQL-type storage (when queries happen ad hoc, or by keys or conditions other than the primary key), ISAM storage (when only the primary key is used to retrieve or filter records and the primary key is not both high-density and sequential), random access (when only the primary key is used to filter or retrieve records, and the keys are high-density and sequential, and you don’t retrieve the whole file on each use), or in sequential files (when you retrieve the whole file in each use).
Data that is not tabular in nature, but which is document-oriented (and which has some sort of primary key) is best stored in a NoSQL or Document-Oriented database.
Data which is going to be stored in a tabular manner or in a document-oriented manner should be stored in a processing queue of some sort.
Large data that doesn’t fit into any of these categories generally goes into a rather unstructured pool of data, currently called a “data lake”.
You will find those who think that all data should be stored in SQL, and people who think that all data should be stored in NoSQL systems. Sheldon believes that both of these groups are wrong. Less specifically, Sheldon believes that anyone who says that everything should be done in any one manner is wrong.
25.6.2. OS
Operating systems can have a large influence on how things are done. OSes fall into a number of categories:
Unix/Linux: Unix is commercial; Linux is the freeware equivalent. Both run on everything. Properly written Unix/Linux programs are fully hardware portable.
Windows: The server version of windows doesn’t need a keyboard or screen. Windows is not fully portable. Serving more users costs more than serving fewer users. There’s a lot of proprietary software here.
IBM: These are mainly mainframe OSes. They support big-iron solutions in which very powerful machines with very wide data paths are thrown at a problem. They include batch programs which will finish their task or restart themselves even after an unplanned reboot.
Embedded real-time operating systems (RTOS): Real-time operating systems can execute tasks at exactly the right time. Embedded systems are those that have no user interface that’s obviously part of a computer.
Sheldon’s advice: Generally, I don’t recommend requiring any specific operating system. The two exceptions are (a) when using big-iron hardware such as an IBM z/Series or Oracle Exadata, you don’t get the whole hardware boost without the OS that knows how to use the specialty hardware, and (b) when you need a real-time solution, call that fact out in the requirements. Real-time operating systems are not as general-purpose as most operating systems, but they react much faster.
25.6.3. Stacks
A “stack” in this context is a collection of programs (operating system, web server, web languages, and specific programs) that “sit on top of each other”, such as the Windows stack (Windows, Internet Information Server, and ASPX or some other server web language, and Microsoft SQL Server), LAMP (Linux, the Apache web server, the MySQL database, and PHP), and Java web service (Linux/Unix/zOS, Apache, a database, Java, and likely Java Server Pages).
25.7. Security
Security falls on a spectrum. Some programs don’t need any, like games. Other products need a lot, like military and banking. Know the required security level, and the probable threat level. In the requirements document, document the visible security requirements in the function requirements, the invisible security requirements in the “nonfunctional requirements”, and the threat levels in the assumptions area.
Outside: How secure your software is from all types of outside attacks. Sheldon’s benchmark: I did some work for a banking system comprising thousands of banks (not just branches). It took them eleven months to patch the holes I was able to get through.
Inside: This is the level of security needed and used inside the building, from none through just as much as Outside security. Ken Ellson’s rule: Your security should be good enough that it will take the bad-guys 40 hours to get through. If they’re going to spend 40 hours on this, they’re just not going to stop. Sheldon’s observation: Ken is correct. The longest it has taken me is 240 hours.
Database: The database may need to be secured, such as internal permission levels and encrypted columns. For instance, passwords may be stored with one-way encryption, so that they can be compared encoded, but can never be decoded.
Code at the user tier: Once code is delivered to the user tier, it’s in the user’s control. Never trust code running at the user tier, such as the JavaScript you sent.
Penetration: Attacks in which there is an attempt at some sort of “penetration” of your system, or the insertion of something into it. The most common form of this is logging into control ports by guessing passwords, and “SQL Injection”, in which parts of SQL commands are sent to data fields, hoping that your program doesn’t protect itself from that.
25.8. Nice Ways In & Out
Consider these during the requirements-gathering phase:
Input validation: Whenever a field is entered, the program should reject invalid types of characters. For instance, in a numeric field, ignore letters. Always check every field for valid input. Checking during data entry is optimal, but not all checks can be run at each keystroke.
Crystal Reports™, Microsoft SSRS, PowerBI, Tableau, and the like: these let you set up a report format, and have that report filled from server data, using parameters. Best practice: Separate the report from the view or procedure that delivers the data. Feel free to specify what goes into the report, including format, but best not to specify a particular reporting program.
Kofax™ and Google Vision: These are scanning and character recognition systems which can scan documents, determine their types, do validation, and put data into the database. Kofax is a complete commercial off-the-shelf (COTS) solution, and Google Vision is a callable library.
If you find any of these (or similar) techniques or products useful, the use of any of these will likely affect the requirements document(s).
25.9. CPU Scaling
Scalable systems allow your system to continue to run once its usage grows.
The Microsoft Windows way: Sends your maintained data to the user’s tier, encrypted, so that the user can’t modify it. The user’s system can reconnect to any of a number of servers, delivering it accurate knowledge of what the state and data is. Pro: Virtually unlimited PC scaling. Con: Extra data transmission. This is called “Horizontal scaling”.
The PHP way: Machines are told which machines to reconnect to. Pro: You can connect a lot of cheap machines quickly. Con: It’s hard for the systems to coordinate with each other, so the problem may have to be broken down. This is also Horizontal scaling.
The Google and Amazon Web Services (AWS) way: Makes copies of the data to each server, so that no one machine needs to communicate with another for most circumstances. This is also Horizontal scaling.
SOA: As discussed above.
The Unix/Linux (and Oracle) way: You can write your application for small machines, and run it on the largest systems built. Pro: Cheap & easy at first. Any level of power may be applied to a problem, a little at a time, without any coding to account for scaling. Con: Requires replacement of machines. You don’t necessarily take full advantage of any special hardware present. This is called Vertical scaling.
The IBM way: Choose a big-iron machine, and take advantage of all of its special features from the get-go. Pro: It’s fast to get going, and there is no accounting for the possibility of scaling. Con: It’s expensive, and you’ve got unused capacity at first.
The notion of scaling is important at requirements time. For instance, if the data and all possible processing power will fit in one cheap machine, then ignore any possibility of scaling. If the number of users, size of data, or complexity of processing can grow without limits, then the system must be built for scalability in the first place. Although it’s not your job as the requirements writer to decide what kind of scaling will be used, it is your job to know and document what kind of scaling might be needed in the future. This can happen in the Assumptions section (for instance, an assumption that there will be few users to start, but that there will be billions later), and/or in the “nonfunctional requirements” (for instance, “Response times shall be within 500ms when fewer than 100,000,000 users are using the system simultaneously.”).
25.10. Database Scaling
When all of your data fits in the same processor as is handling your web-site, there’s nothing to worry about. If the workload gets too big, then it’s time to separate the database from the web server. If you’re running a database back-end to desktop applications, then you’re already in this circumstance. At some point, the data or the processing load may get to the point where a single x86-class machine can’t handle the load any more. At this point, there are several options to grow the system.
One method to switch to a federated database. In a federated database system, there is one processor that acts as the database server, but it’s not the whole server. It’s mainly a facade for the rest of the database server. In a typical system, there may be one front-end server, with 16 processors behind it. Whatever work you give the federated server, that work is split. For instance, let’s say you execute the SQL command “SELECT SUM(balance) FROM Account”. That asks the system to look at every record in the Account table in the database, adds up the Balance column, and reports the result. This means that every record in the Account table has to be read. That can take a while in a regular database server. But in a federated server system, that Account table has somehow been split up. For instance, if we have constituent servers numbered 0 through 15, one way of splitting up the work might be to divide the account number by 16, and use the remainder of that division (called the modulus). For instance, for account #20, 20÷16 is 1 remainder 4. So the processor number we would use for that record is 4. All this happens behind your back. In this example, processor #1 would sum the records for accounts numbered 1, 17, 33, and so on. Processor #2 would sum the account records for accounts numbered 2, 18, 34, and so on. All 16 back-end processors would come up with 16 sums, and the front-end processor would add those 16 sums together, and return the result. Thus, the 17 processors can work almost 16 times as fast as a single processor for this type of work. Pro: This type of processor stays “consistent”, in that there is only one copy of the data, so if I ask the total of all balances, and you ask the total of all balances, we’re going to get the same answer, if there are no changes in the intervening time. Con: However, let’s say that just before I ask for the sum of all account balances, someone else starts a transaction which will move money into or out of an account, locking or freezing one of the account records. The processor handling that account will hold my request until the locking transaction is complete, which will mean that one of the 16 sums to the main processor will be delayed, which will mean that my whole answer will be delayed. This type of set-up is ideal for when data consistency is of paramount importance. Although the example and explanation show an SQL database, there are equivalents for NoSQL databases.
The second method of getting faster results is to have fully replicated data. For instance, let’s say that we have a big search engine site. We have thousands or millions of web crawlers (programs that search the web in some predictable manner), looking for web-site contents and links. They add to or update our database of everything that’s out there on the web, in some sort of majorly indexed manner. We also have thousands or millions of search engines, doing searches on that database. Do we want millions of servers reading from a single database and millions of crawlers writing to this database all at once? Probably not. That would be quite a load, and even the fastest server is unlikely to be able to keep up. So, what’s done is that there are Replicator servers, whose job it is to make copies of the indexed web database. Each of those search engines, or more likely, each gang of search engines shares a copy of the web database, showing the contents of the web as it is right now, or a few minutes ago, or a few hours ago. Not all of these copies will be made at once. Some copies will be newer than others. So, if I do a search for some trending topic, my search may run on a server with a 10-minute old copy of the internet, and when you do the same search at the same time, your search may run with a 5-minute old copy of the internet. Thus, you and I may get differing results, even though we ran our queries at the exact same time. This is called “eventual consistency” and “replicated data”. Pro: This type of system is very fast, because nobody waits for anything, except during a copy, and even then, if there are copies which are switched out, nobody waits at all. Con: The data has no guarantee of consistency. This type of set-up is ideal for mass searches of big data without the need for consistency over a short period of time.
There are hybrid databases (both SQL and NoSQL) in which there is apparently one copy of the database, but there are two or more copies behind the scenes, and there is a process (or processes) to merge the data. There is some replication, and synchronization processes are running all the time to keep that data as synchronized as is feasible, but until each synchronization completes, there are minor inconsistencies. A social media web-site will typically run this way. It may take a few seconds for my comments to show up in your feed. Pro: The system gets a good deal of speed, and a good deal of consistency. Con: It’s not the fastest, and it’s not 100% consistent all the time. These systems are also called “eventual consistency”, because the data will sync up soon. Have you ever ordered something that the system says it has when it starts processing your order, and then when you get the delivery, there’s a message that says “Sorry, we were out of stock”? That’s the result of “eventual consistency” being used where full consistency should have been used.
So, why this great level of detail in this database engineering matter in a requirements engineering book? Because you need to know what the consistency requirements are for the system you’re building. What are the ramifications to an inconsistency? If, in the case of a big search engine, speed is more important than consistency, go that way. If, in the case of a bank, consistency is more important than speed, go that way. If, in the case of social media, you want the best of both worlds, with being a bit out of sync is fine, go that way. But know what you need, and document that need.
25.11. In-house, Cloud, or Edge?
Unless you’re building an embedded system, it doesn’t much matter where the computer is, so it’s not going to be a requirements issue whether the computer system is in-house, in the cloud, or “on the edge”, meaning that parts are in-house and parts are in the cloud. There are a few exceptions:
- Embedded systems need to be embedded (of course).
- Security concerns may mean that data can’t leave the premises.
- Real-time systems typically can’t stand the lag to get to or from the internet.
- If the system is isolated or otherwise incommunicado, it needs to be self-sufficient.
- Management or a customer contract dictates one scheme or another.
25.12. How Things Can Go Wrong
Get one of these design decisions wrong, and you’re likely to violate one of the edges of the engineering triangle, in that…
- Good: The project may not do what it needs to do (or may not do it well),
- Cheap: The project may cost more than it should to develop, use, and/or maintain; and/or
- Fast: The project may take too long to deliver and/or the project may take too long to deliver and/or run.