- administrivia - midpoint surveys still outstanding - have 1 so far - this is your chance to influence the direction of the class - Q3 next time: threads - P3 handed out next time - P3 is a group project: please pick your groups, or risk me picking them for you! - News o' the day: - Wired article on "Top 10 Software Bugs of All Time" - Worth reading - list includes: - buffer overflows - improper data validation - numerical errors - improper initialization - race conditions - the big news? All of these are still with us... :-P - Design principle o' the day: - Orthagonality: - Isolation of functionality into simple, non-interacting, complete, universal set of methods - API should be designed to be: - simple -- each method does a small thing - non-interacting -- each method affects only its target state, and no other state (no extraneous side effects) - complete -- all methods, taken together, offer all necessary functionality - universal -- every related class supports every method * minimal -- smallest set of operations you can get by with (This one is often sacrificed in the name of utility) - examples: - simple: get, put, size, iterator - not simple: putAndGetIterator(), sortBackward() - simple: WorldSimulator.act(), RLAgent.pickAction - not simple: WorldSimulator.doForward(), WorldSimulator.doTurnClockWise(), etc.; RLAgent.doExperiment - non-interacting: Date.setDay, setHour, setMin; RLAgent.pickAction and RLAgent.updateModel; GridWorld2d.set() and WorldSimulator.setGoalState() - complete: get, set, size, iterator - undercomplete: put, iterator - overcomplete: put, add, append, addAndSort; size, length, nElements - Note: overcomplete can be useful, but beware of cruft - universal: - equals, hashCode - java.util: get, put, add, size, iterator - javax.swing: add, addActionListener, get*, set*, repaint - non-universal: addToMiddleOfList, numElements - OO was developed, in part, to support orthagonality - inheritance => universality - encapsulation encourages non-interaction - older examples of orthagonality - in UNIX, everything looks like a file - can read(), write(), flush(), open(), and close() on files, pipes, sockets, fifos, etc. - many CPUs have orthagonal instruction sets - small set of fundamental operations - every operation can be run in every addressing mode - client-server design pattern - basic idea: - single, central _server_ process/machine - many different _client_ processes/machines - each client issues _requests_ to the server - the server receives and computes answer to request and sends _response_ back to one or more clients - separation of responsibility - client provides a _view_ to the user - server provides a data store (i.e., _model_) - allows efficient use of distributed resources - allows multiple user/client support - basic architecture: every machine has an _address_, a set of _ports_ for that address, and a set of different _protocols_ - to make a connection, both ends have to agree on all three of these - _server_ starts up on a fixed machine, binds to a port and waits - _client_ starts up on a different machine, issues a request to connect to a target address/port. - server chooses whether to _accept_ or _reject_ the connection - at server end: - new ServerSocket(int port) -- create a ServerSocket object attached to a port on the current machine - ServerSocket.accept() -- waits for a remote client to try to connect to the current port; returns a corresponding Socket object when it gets a connection - at this point, server should spin off a separate thread, so that it doesn't spend all of its time dealing with one connection and ignoring all others - Socket().getInputStream() -- data coming in to server from client - Socket().getOutputStream() -- data going out to client from server - At client end: - new Socket(String host, int port): create a socket on the client end, connected to the server machine/port - Socket().getInputStream() -- data from server to client - Socket().getOutputStream() -- data from client to server - client probably wants to use a thread to listen to getInputStream() -- otherwise, all UI activity is blocked, waiting for the input stream to produce some data - at this point, both ends can use read/write on streams to communicate - both should use flush() on output streams to ensure that data is sent