7 ms·
Ask HN: How do you think about programs?
I've been trying to learn Apple's Cocoa libraries for a few weeks now. I found that writing small applications is a piece of cake, but when I start writing larger apps I tend to get lost in the complexity of my own creation.
My question is this: how do you think about your applications while you're writing code?
Hillegass uses object diagrams (is that what they're called?) to represent relationships between objects in his apps. How do you do it? More importantly, do you use a pen and paper to design your programs up-front (my preferred method) or do you jump right into the code? Do you use diagramming tools to create your object diagrams? Do you write specs? Do you write notes to yourself?
What I'm trying to find out here is an effective method for creating a high level overview of the app I'm working on so that I can tape it to the wall and look at it to figure out what I have to do next. My usual method of writing down TODOs in random notebooks and losing them at college doesn't seem to be working out that well.
- karim 18y ago"Divide each difficulty into as many parts as is feasible and necessary to resolve it." René Descartes I break the program in functional parts that are easier to grasp and I assemble those parts only after having written tests for those parts.
- lallysingh 18y agoI've tried a lot of systems (omni* and a few others), but here are what stick with me: Emacs Org-Mode for the day-to-day stuff that I want to keep in front of me when I'm writing code. It's essentially perfect for it. Using the tables with pasted-in code is utterly fantastic (hint: replace-regex '^' with '|> ' and it'll keep your indentation before you hit tab and tablify the code). Org mode does tables, outlines, todo lists, agendas, mostly everything a programmer's going to want day to day. For higher-level planning, I leave the workstation. Get a cup of coffee/soda/juice/who-are-we-kidding-its-coffee and a table away from computers. A moleskine (the squared one, with the grid layout) and a good pen (I like these $4 pilot extra-fine vballs) is what I use. Relaxing music in noise-canceling headphones FTW. Do yourself a favor and begin with the habit of writing the date on a page when you start writing on it. It's useful for you to see your progress over time, and it can be helpful later in patent disputes. As for the thinking process itself, here's my heuristic: - Small apps are mostly driven by a framework you just use (probably some MFC/DI garbage). Keep your code clean & organized, and work a little to keep the expected chaos from working with always-mysterious frameworks contained. E.g. don't ever trust the framework to handle your model code for you. Use proxy classes, multiple inheritance, whatever to firewall yourself from that chaos. - Medium apps have enough internal structure to get past the cognitive mass of the framework. There, you end up with a top-level abstraction that structures the app. Be it a pipeline, a set of command objects, or a data structure you maintain, there's one big one and the app is structured by it. - Large apps have a few of these. They're independent subsystems and you firewall their interactions the best you can. Unless you've got the time/labor for large-scale refactoring, you generally just try to keep the abstractional dams from breaking. In those cases, I usually try to get some middleware in there, so I can easily handle stubs, testing, and interactive use with each. If you've got a REPL, you can avoid it, but in C++/Java, it can really help.
- lallysingh 18y agoEdit: s/MFC/MVC/. Freudian slip there.
- rubentopo 18y agoNo one method works all the time, this depends on the paradigm of the target language. At least i can't use one method. One thing that makes it much easier (at least for me) is trying to use dependency injection, otherwise i get lost. Misko Hevery said it better. http://misko.hevery.com/2008/11/11/clean-code-talks-dependency-injection/ http://misko.hevery.com/2008/11/11/clean-code-talks-dependen...
- frig 18y agoThis is cocoa-specific, though some of it generalizes. I'm not a huge fan of the Hillegrass book for actual beginners, but sadly there's not a better book out, yet; it's almost easiest to learn some other, better-documented GUI application framework, then come back to Cocoa (assuming you have time). Assuming you don't have that kind of time, though, here's my recommendations: Cocoa development also depends heavily on the workings of NSApplication, and it's a good idea to stop and read up on how that works; it's super helpful to actually know what's going on between the points where the code you wrote is being used, and to understand that you need to have a working understanding of how NSApplication is structured. Apple has ok docs on this (I'd start by reading up on NSRunLoop, then looking up anything you encounter you don't understand), but nothing amazing. Once you've gotten that understanding, you'll have a much easier time understanding what you have to do to make an application do what you want. Now we move on to handling specific applications. I suggest the following design algorithm: "Simultaneously", start figuring out your application's user interface and its data model. I say "simultaneously" but it's really a bit of a back-and-forth. For example, you decide you're going to write a blogging client (I think this is an example in Hillegrass's book?). So, ask yourself what data items does a blog post typically have? Provisional answer: title and body. What user interface elements do you need for a blog post? The data model dictates those: right now, a text field for title and a larger text field for the body. If we were going to be more realistic we'd probably want a richer data model (some "authored by" field, some field for "tags" or "categories", etc.) and a more-complicated user interface to match. If you hit a "stopping point" in this process -- meaning, a point @ which you are satisfied that your data model covers everything it needs to and your user interface elements are complete -- we can move on to the next step. The next step is getting a sheet of paper, or a whiteboard, etc., and putting up some representation of each user interface (eg: each type of window or dialog), with lots of space between them. Next, you go through each user interface item and ask - "what information does this item need to display itself properly"? (eg: a blog-post-editing view needs the blog post's data object.) You should annotate each user interface item with some representation of the data item(s) it needs to render itself. Once you've done that, you make another pass through each user interface element, asking the question: - from this user interface item (say, the blog post editing window), which other user interface items can I get to? Which other user interface items can I be arriving from? Once you've done that, you go back through and ask the following question for each "entry path" into a user interface item: - for each entry path into this user interface item, what information would I need to set up this user interface item correctly? (for example: if you're editing an existing post, you need to have the data object corresponding to the post you're editing; if you're creating a new post, maybe you need nothing, or maybe you need some kind of placeholder reference to the post-to-be-created) Note this is DIFFERENT from the step where you listed the data item(s) the user interface item needed to render itself. For example, to render itself, the blog-post-editing-view needs SOME blog post data object; however, if you're moving from a list of all blog posts to editing a specific blog post, the blog post editing view needs THAT SPECIFIC BLOG POST. Once you've done that, you make a final pass, asking the following question for each "exit" path: - for each exit path from a user interface item, can I supply the information the user interface item I'm entering needs? (ie: if you're leaving the "blog posts" listing view to go edit a blog post, the blog-post-editing-view needs the blog post's data object; can you supply it?) For example: if I'm leaving the "blog post listing view" and heading into the "blog post editing view" to edit a specific blog post, then the "blog post editing view" needs to be given that specific blog post to render. Is it possible to get that information from the "blog post listing view" to the "blog post editing view"? Yes, b/c the "blog post listing view" knows which "blog post object" you selected. You'll find yourself answering "no" when you have what I'd call a long-distance dependency in your user interface workflow: to get to view C from view A you pass through B, but the naive implementation of B doesn't let you pass along some needed bit of information from A to C; this is probably the single-most-common source of frustration/head-slapping when you're first learning Cocoa (or any GUI app). Hopefully, you'll finish all this work and have found no unpleasant surprises (ie: you have exhaustively analyzed your program's workflow using the above information and all information you need can be delivered to where it is needed). If you've got some gaps -- user interface modes that can't get information they need -- you should fix your diagram (adding extra data-items to user interfaces as-needed). Once you're done with this you should more or less have the "Model" and "View" tiers of your application figured out -- the "model" objects are all the data model objects, and the "view" tier is all the user interface items you've made (eg: all the separate .nib files). You can go ahead and write the data model classes and create the .nib files now. From here, building out skeletal controllers is pretty easy: for each user interface item, you build out a controller class, making sure it has fields for each user interface element in your user interface item (eg: it has one field each for the "title" text field and the "post" text field) and one field for each data item it has to know about (eg: a "post editing view" controller has a field for a "blog post" data object). You now have to add the actual logic to the controller. This comes in three main forms: - you add code to synchronize the user-interface with the data item (ie: if I've got this "blog post" data item, write a method that makes the on-screen "title" field == the "title" field in the "blog post" data item, and so on) - you add code to synchronize the data model with the user interface (ie: if the on-screen "blog post" has such-and-such title and such-and-such post, this code makes the "blog post" data item's fields the same) - you add code for handling each "entry" and "exit" from the corresponding view (eg: one method for setting up a view to start editing an existing blog post, one method for setting up a view to start creating a new blog post, and some methods to handle closing-the-view-and-saving-your-work) If get through with all the above, you're going to be pretty close to finished with whatever application you're writing; the last steps are dealing with stuff like the "startup" code (when the program starts, how does it bootstrap itself into a user interface state?) and similar tasks. The above process is extremely heavyweight, and I don't pretend to use it anymore -- I might sketch out particularly-complicated parts, but not the whole app -- but I do recommend mocking up at least your first few progs with it; it's a good learning exercise, and it's a little more "obvious" than a pure "object diagram".
- lyime 18y agoOmni Graffle and Mindmaps. Pen and Paper works too.
- pbrown 18y agoI started with post-it notes, but kept losing them too. Now I use Freemind, and have a really big whiteboard (of the manual variety) on the wall in my office. You mentioned you're having a problem with big apps. I'm the same way. At the risk of sounding condescending (which I'm not) break the big app down into a bunch of small apps (features). I find this works for me in two ways. 1.) I can code the small apps easier (and then ideally put them together into the big app). and 2.) If I find I'm getting feature creep, it's easier to dump 1 or 2 "small" apps rather than rethinking the whole project.
- jacquesm 18y agoI outline first, then turn the outline into the program. Items on the outline are 'actions' or 'data', data goes to the top of the outline, actions follow. I hope that's clear and that it will work for you, it works like a charm for me, even for very large projects. Outline editors are a dime a dozen, not sure which ones you could use on the mac though...