300 likes | 309 Views
Architecture Implementation. Examples. The process. It’s a little absurd to throw up a bunch of code on a presentation and expect people to be able to read it quickly. The process.
E N D
Architecture Implementation Examples
The process... • It’s a little absurd to throw up a bunch of code on a presentation and expect people to be able to read it quickly...
The process... • Instead, I’ll go over the thought-processes and decisions made by the authors when writing the code in the book. • I’ve written some pseudocode that attempts to capture the architecture’s implementation concisely • I encourage anyone with their text to follow along with the real code and note the differences
Decisions: Which Framework? - Say we need to implement this in java - The java.io package and the java.nio package are both viable options - java.nio is generally faster, but more complicated. - java.io should do considering the relatively small size of our data and its simplicity compared to java.nio
Decisions: In-Process vs. Multiprocess - The difference is simple: - Do we want our three filters to be “piped” within a single Java program using java.io? - This is the “in-process” way of doing things
In-Process vs. Multiprocess -Or do we want to just create three simple Java applications that will be our filters? - and then use each of those “processes” in the command line with the operating system’s pipes (e.g. the unix | command) java GetBurnRate | java ComputeNewValues | DisplayNewValues
In-Process vs. Multiprocess - The book argues that multiprocess is simpler as it means less code will need to be written - There are arguments to be made for both methods though...
Where to start writing code? - This is actually a really difficult question a lot of the time when writing code. - The fact that we’ve chosen the pipe-and-filter architecture for our code makes it simple. - Pipe-and-filter runs left-to-right. That is, more or less, the direction we should write our code in.
Where to start writing code? - Each of the filters could feasibly be implemented in any order - But what about testing? - You’ll be creating more work for yourself if you have to create mock data, stubs and skeletons for the earlier parts of the code merely to make sure that the code you’re implementing is working properly.
Pipe-and-Filter Criticism - This specific example is simple - But the architecture didn’t specify a few things - What if we used an XML format for data in one filter and a line-based format for data in another? - These types of data mismatches are obvious, but more subtle mismatches can occur
Pipe-and-Filter Criticism - Also - what if the operating system you’re using doesn’t have the right pipe operator? - Example? MS-DOS - You now no longer have the option of multi-process and are forced to use Java’s io for pipes.
Leftmost (GetBurnRate) public class GetBurnRate { userBurnRate = readFromStdIn(...); sendToStdOut(userBurnRate); } - This ignores many important things - Try/catches - Integer/string conversions
Middle (ComputeNewValues) public class CalcNewValues { String input = readFromStdIn() if (altitude <= 0) printToStdOut(“Game over”); else if (burnRate > fuel) printToStdOut(“Out of fuel”); else { landerState = calculateNewLanderState(); printToStdOut(landerState); }
Rightmost (DisplayValues) public class DisplayValues { switch(readFirstCharFromStdIn()) { case ‘a’: printToStdOut(“Altitude: “ + value); … } }
Lunar Lander as Lightweight C2 Framework - The book once again simplifies their code by using the simpler of two options: lightweight C2 Framework instead of the Flexible C2 Framework
Clock GameState Bus GameLogic GUI
Bottom-Up Programming - again, we can implement each component in any order - however, it makes the most practical sense to start with the code that has no or few dependencies and work our way up - the diagram disagrees with this intuitively, because the components with the least dependencies are actually on top
Clock GameState Bus GameLogic GUI Working on components in this order is actually “Bottom-up” programming
Representing the Lander’s State - the first step in this fashion is to represent the game state - This class needs to contain the information about our lunar lander - It also needs methods for requesting to read or update the game’s state
public class GameState extends ComponentThread { protected void handle(Request r) { if (r.name().equals(“updateGameState”)) { updateInternalGameState(r); } send(createStateNotification); } private void updateInternalGameState(Request r) { if(r.hasParameter(“altitude”)) { setAltitude(r.getParameter(“altitude”); else if(r.hasParameter(“fuel”) { setFuel(r.getParameter(“fuel”); } … } protected Notification createStateNotification() { // creates notification object filled with key-value pairs of the game’s state (altitude, fuel, velocity, time, burnRate…) } }
Clock GameState Bus GameLogic GUI
A Simple Clock public class Clock extends ComponentThread { public void start() { Thread clockThread = new Thread() { public void run() { for (;ever;) { sleepForFiveSeconds(); sendClockTickNotification(); } } ... }
Clock GameState Bus GameLogic GUI The necessary dependencies have been created. Now the remaining components can be built.
public class GameLogic extends ComponentThread { public void start() { super.start(); Request r = new Request(“getGameState”); send(r); // Gets us the initial GameState } protected void handle(Notification n) { // This Notification will be recieved whenever a request is made if(n.name().equals(“gameState”)) { retrieveEachState(n); // retrieves values for altitude, fuel, velocity, etc. if they are available } else if (n.name().equals(“clockTick”)) { // A tick has occurred, we should update the game state updateGameState(); landedSafely = didLunarLand(); sendUpdatedGameStateRequest(); } }
public glass GUI extends ComponentThread { public void start() { createProcessInputThread().start(); } public void processInput() { showGameInstructions(); } protected void handle(Notification n) { if (n.name().equals(“gameState”)) { printAllGameStateValues(n); } } private void printAllGameStateValues(n) { if(n.hasParameter(“altitude”)) { print(n.getParameter(“altitude”); } else if (...) { … } else if (n.hasParamter(“landedSafely”) { if (n.getParameter(“landedSafely”)) { print(“You have landed safely.”); } } } }
public class LunarLander { public static void main(String[] args) { Architecture lunarLander = new SimpleArchitecture(“LunarLander”); Compononent clock = new Clock(); Component gameState = new GameState(); Componenet gameLogic = new GameLogic(); Component gui = new GUI(); Connector bus = new ConnectorThread(“bus”); lunarLander.addComponent(clock, gameState, gameLogic, gui); lunarLander.addConnector(bus); // Glue the pieces together in the appropriate order lunarLander.weld(clock, bus); lunarLander.weld(gameState, bus); lunarLander.weld(bus, gameLogic); lunarLander.weld(bus, gui); // Start the application lunarLander.start(); } }
What do you think? Which of the two architectures was easier to implement?
What do you think? Which of the two architectures was easier to implement? - Pipe-and-filter required less code, had a shallower learning curve - C2 enforced much harsher restrictions. - This can be thought of as a bad thing, but architects are supposed to think of the big picture - Harsh restrictions give programmers better, more consistent guidelines leading to less bugs and more readable code