Sunday, December 11, 2011

Running Clojure

I ran across a(nother) article today about jumping into clojure. It was full of misconceptions and half truths, but if it gets people into running and playing with clojure that otherwise would not, then I guess I can overlook them.

One thing that I *always* see though, is how to run the REPL. It's always:

java -cp clojure-1.3.0.jar clojure.main

Which works just fine. What I don't understand is why no one seems to know this easier way:

java -jar clojure-1.3.0.jar

Which also works, and is shorter, and somewhat more idiomatic, IMO. It even works on, , Windows.

c:\clojure-1.3.0>java -jar clojure-1.3.0.jar
Clojure 1.3.0
user=> (+ 1 2)
3




Saturday, November 19, 2011

Project Euler #4


Did problem #4 today. Find the largest product of 2 three digits that is a palindrome.

This one wasn't too hard (given that I don't know clojure well enough to not have to scour docs for the order of arguments and such). First made a function that just returns all the products of 100...999, (actually 101; no product of 100 * anything can be a palindrome) as a list of 2 item vectors of the product and its palindrome, as strings.

Then ran it through a filter which removed all the non-palindromes. Then a map to get one of the elements of the vector. Then mapped it to an integer. Then applied max to that.

However, I hated that solution.

So, I improved upon it slightly by reversing the range to start from the high point and counting down, thinking that I could generate the palindromes in pre-sorted order, and I could just take the first one. Unfortunately, my plan did not work. But, I did realize how to better use the for comprehension to do the filtering for me, rather than after the fact, so I didn't bother doing as many int -> string -> int conversions, which did make it faster. I also eliminated the function wrapping the for, and just stuck it inline. So what I ended up with is here:

(apply max (for [a (range 1000 101 -1) b (range 1000 a -1)
:when (=
(.toString (* a b))
(apply str (reverse (.toString (* a b)))))] (* a b)))



Wednesday, November 16, 2011

Project Euler in Clojure

Problem 3; what's the biggest prime factor of some big #?

I went a lot of ways here, but finally ended up with the following. First, I made a function which would factor a number. I poked at this a lot of times before I ended up on the for comprehension, which I'm not sure is the best way by far, but I wanted to play with it. It runs up a counter from 2 to the sqrt(target), and if the target MOD the number is 0, returns the number and the "other" factor in a list, then flattens the list of lists when done. (Ideas welcome for removing the flatten... something with cons/conj?)

Then I wrote a "prime" method which tells me if a number is prime. It does this by just factoring the number using my factor func, then counts the factors. If it's 2, it's prime (1 and the # itself).

Then it was a simple matter of calling factor on my big #, filtering the factors returned through the prime method, and calling max on the result. Ah, but max doesn't take a seq... so I had to 'apply' max to the result. Lots of lessons learned here, and looking for advice on how this could be more clojurific.

(defn factor [m] (flatten (for [a (range 1 (Math/sqrt m)) :when (zero? (mod m a))] (list a (/ m a)))))

(defn prime [n] (= 2 (count (factor n))))

(apply max (filter prime (factor 600851475143)))

Learning Clojure

I've started my journey down clojure land. 4clojure and Project Euler are my first goals. Started with project Euler. Here are my first couple solutions. Critiques on clojure idioms, style, optimizations welcome.

#1. http://projecteuler.net/problem=1
Find the sum of all the multiples of 3 or 5 below 1000.

(reduce + (filter #(or (zero? (mod % 3)) (zero? (mod % 5))) (range 1 1000)))



#2. http://projecteuler.net/problem=2
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

My solution:

(defn fib [x]
(cond
(<= x 3) x
:else (+ (fib (- x 2)) (fib (- x 1)))))

(reduce + (filter even? (take-while #(< % 4000000) (map fib (iterate inc 1)))))

The unusual form of fibonacci is due to the requirement; the sequence starts with 1 and 2 instead of 0 and 1, so the first 3 terms are 1,2,3 so that is a teensy teensy point of optimization.

I actually started with a range, but that starts with 0 which isn't quite right, and if you have a starting point (say... 1), on a range, you need an ending point. And while I could have used an obviously too high end point (which is actually what I started with), it didn't feel right, so I dug around for the function I knew existed, but couldn't locate.... until I found iterate.

Sunday, October 19, 2008

Where are all the women?

I've seen a lot of articles lately about women in IT, computer science classes, technical industries, etc.  The lack of them, the declining numbers, the declining %'s, how to get more of them, how to pander to their tastes, etc.

My question is, why?  Why all the extra energy for just women?   Are they magical in some way that I'm not aware of?  More deserving of special treatment?  Somehow "better" than any other group that ISN'T getting all this love?  Do the people writing these articles have some sort of ulterior motive of their ultimate porn fantasy?  Why not "Where are all the [insert demographic here]"?

I don't THINK I'm sexist*, but all I want from coworkers and people in the IT (or ANY) industry is people I can get along with and can do the job.  Women, men, Antareans, amoebas, fungi; I don't care.  Do your job, don't keep me from doing mine, help me when you can and I'll do the same.  




* Before you comment, me being sexist would be me saying I want fewer women or to somehow make it harder for them, which I'm not.  What I'm saying here is... I don't care if there are more, OR fewer.  All I want is qualified people.

Monday, October 13, 2008

Stuff I Did Today

It was officially a holiday for me, so I didn't get any real work done.  That's unusual; if I'm home, I usually work.  Mostly off the books.

  • I can't seem to be able to ask a question without people thinking I have an ulterior motive, thinking I'm complaining about something, or something else negative.  I guess I only have myself to blame, but I'm honestly generally just asking.   I think I've figured out a way to try and not trigger everyone's eye-rolling reaction to me; we'll see if it works.  I often wonder if I'm slightly autistic because I appear to be very, very bad at reading social cues.  I thought working from home would help; it pretty much hasn't, but possibly made it worse.
  • I learned (or rather, read), that diesel engines don't have a throttle.  They adjust power by varying fuel/air ratios.  My next car will probably be a diesel.
  • Downloaded a free FPS and played that.  Fun, no subscription, and satisfies my gaming urge.

Wednesday, October 8, 2008

Stuff I Did Today

  • Was completely misunderstood.  By 2 people.  On 2 different circumstances.  Sometimes working from home sucks.
  • Did unnatural things to our QA box with gobs of data it'd never seen before.  CPU was at 100% and load averages hovered above 10 a good bit of the day.
That's about it.  BigDataLoadTesting took my whole day.

Tuesday, October 7, 2008

Stuff I did today

  • Installed ruby on our QA box.  Finally.
  • Navigated treacherous object dependencies and got a bulk data generation script running well enough to not puke out internally inconsistent data.
  • Learned about Oracle's bulk loader.
  • Sicced a new employee on an irksome bug report like a dog on a pork chop.
A good day.  Even managed to squeak out a few "good dad" moments.

Sunday, July 6, 2008

What is the singular of...

As I was reading this BBC story, "How to solve the British maths problem?"[1] I was reminded of my numerous British friends and colleagues always ribbing me (a United States citizen) how bad my English was. That was, of course, in the context of their British English since I think my American English is at least in the top quartile in terms of correctness[2].

As I read the story I was left with one question. In the UK, how much, or big, or many, is one "math"?







[1]http://news.bbc.co.uk/2/hi/uk_news/magazine/7435023.stm
[2] Yes, I fully expect to have errors in this post pointed out. Thanks.


Thursday, May 22, 2008

Full Text Justification is Abysmal


I hate full text justification. It works ok for newspapers since their columns are not wide, and they typically do not use "big words". So, the difference from line to line between letters and words aren't noticeable. Also TeX and LaTeX seem to get it right, but that's because TeX and family obey typesetting rules that have been carefully tweaked, honed, and perfected over the past 500 years.

But then came WYSIWYG, and everyone from "HTML Programmer" (snort) through administrative assitant through CEO thinks they suddenly have insight into what looks better. And just add insult to injury, we get 1680x1050 resolution monitors with ClearType font smoothing and...

it   looks   like   I   printed    it     on         my     9     pin     Epson     dot     matrix     from     20     years     ago.


The problem is especially bad on technical blogs and Wikis since we techies DO use really big words; not because we're that smart (although some are, just not me), but because we tend to talk in code, and our code uses big words, or directories, or class names, or, or or... The result is certainly not unreadable, but very sophomoric in impression.

If you have a blog or run a wiki and can control these things, don't use full text justification. Yeah, it was cool in 8'th grade with Scripsit to see the blinkenlights magically put text to paper and spread it out to the edge, but these days it just looks like an 8'th grader wrote it. Using Scripsit.



(I'm not a Luddite, really.)




Wednesday, May 21, 2008

Lift Diary, Day 1

I'm trying to learn Scala, and /lift/. The ultimate goal really IS to learn something, but as a way to accomplish that, I'm going to use a website that I maintain (currently java, webwork, and ibatis) as a template. Rewrite that (or significant, not-necessarily-production-quality parts of it), and I'll consider it a success.

As I do various things along this journey, I plan on jotting them down here, so please forgive the inevitable sentence fragments, missing links, misconceptions, etc. This is more a jot pad of what I'm doing, as I do it, not a finalized tutorial for anyone following me.

So, on to it then.

* Download and install the latest Scala (2.7.1 final) at http://www.scala-lang.org/downloads/. I'm using Windows for this. Yeah, I know.

* Setup the path, etc.

* Try it out.


c:\tmp>scala
Welcome to Scala version 2.7.1.final (Java HotSpot(TM) Client VM, Java 1.6.0_05).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object HelloWorld {
| def main(args: Array[String]) {
| println("hello, world")
| }
| }
defined module HelloWorld

scala> HelloWorld.main(null)
hello, world


Success, but I expected that.

* Download /lift/. What the deuce? You don't download lift, you let maven do it. (http://liftweb.net/index.php/HowTo_start_a_new_liftwebapp) Ok, no problem, I use maven roughly daily for my 'real work', so I'm ok with that.

I've used the command line below, all on one line, indents are simply for looks.


mvn archetype:generate -U
-DarchetypeGroupId=net.liftweb
-DarchetypeArtifactId=lift-archetype-basic
-DarchetypeVersion=0.8
-DremoteRepositories=http://scala-tools.org/repo-releases
-DgroupId=net.liftweb.hello
-DartifactId=liftdiary


Not mentioned on the wiki, it asks for a version, then asks for confirmation for some properties its set, then completes.

(I've asked permission (since I'm kind and polite) to edit the wiki, so I can just set things right as I find them, rather than gripe about them here. Also, I've asked David if he wants me to just wiki-ize this whole experience somewhere ON the lift wiki. We'll see how that goes.)


* mvn install jetty:run

Works fine. Now to figure out how to make my OWN web app, and not blindly follow the "do this, do this, do this" pages.

Sunday, May 18, 2008

Culture Clash with Python

I first looked at Python around 1997, for reasons lost to my ever failing memory, but already being a rather big perl-head by then, I didn't go much past the "Hrm, neat" stage.

I've since decided to give it a real go and am studying a bit from online sources. On one hand there are aspects I really like (large extensive library, big support, stable; and even some aspects of the Python "way", since sometimes, but not always, TMTOWTDI is a PITA.

There is one aspect though that just really clashes with me; the community is VERY quick to point out how you're wrong. It doesn't matter about what, it's just you're wrong. I've found that most of the time, I am, but there's this absoluteist tone that I sense that makes me completely understand why the community has the "Pythonista" term applied.

For example, if you want to join a list with a delimeter, the way to do that is like so: string_delimeter.join(<list, tuple, etc.>) # i.e. ", ".join([1, 3, 4, 7, 10])

Ok, that's just a bit backwards from what I'm used to. I want to join THE LIST with the delimeter. It's a small cognitive dissonance, but it's there. When looking at the FAQ about this, it says ... I'm wrong. No, that's not what I want to do. The exact quote is:

The second objection is typically cast as: “I am really telling a sequence to join its members together with a string constant”. Sadly, you aren’t.

Well, yes, yes I am. Like I said, a small nit, but it could have been phrased in less absolutist verbiage, (and the counter example of "split" is inconsistent with what it's saying, but I digress). Ok, so I get past that. (And there is another less odd looking, but less "OOish" way of doing that if I find I can't stand it. So Python ISN'T just 1 way to do it for everything after all!)

So, playing around, I wonder what happens when I try to join a list, err, sorry, "telling my delimeter to iterate my list and insert itself" (rolls eyes), when it contains the equavalent of a null, namely Python's "None".

", ".join(['a', None, 'b']) # => a,,b?

Nope. Exception. Ok, I can accept that None has no default conversion to a string, and I can accept that there's no easy way to do it (Is there? If there is, IRC folk didn't know, and told me I was wrong for even deigning to ask), but I find this behavior a bit irritating. What was the result when I mentioned this? Not that I'm expecting the wrong thing (I am), or even that I was quick to jump the gun to find this irritating (I was), but rather, I don't find it irritating. Excuse me? I'm pretty sure that I do. "Nope, you don't."

Then there's the PEP standard that calls for no more than 80 character lines. I've been programming professionally awhile, and 132 was all the rage almost 30 years ago. There does seem to be some debate about this, and going over my latest java project my line length averages 37 chars (over some 100k lines of code) so I doubt this would really affect me in any meaningful way, and too, I doubt I'm going to be putting any code into Python's already outstanding standard library, but the discussion around it was just what I've come to find out as typical.

I happened to come into IRC when this debate was going on, and although it was mostly good natured, one of the reasons for 80 is that anything over 80 is unreadable. Not, "*I* find it hard to read over 80 character lines.", or even "GUIDO hates it", but >80 is just absolutely unreadable, for anyone. Questioning that, or even mentioning that YOU can do fine with 132, 150, 180, 250 character lines just about has you burned at the stake since you obviously do not, and cannot float like a small stone.

Lastly, and this is probably confirmation bias, but whenever I come across a blog post comparing, contrasting, teaching, explaining, or anything with a programming language, there is almost inevitably the "Why don't you try it in Python?", "X sucks, you should do this in Python", "Python does this all better, see?" set of bleats and whines. It is the same tenor as the nice young men in their white shirts and black ties coming to my door trying to push their version of God on me. Actually, now that I write that I DO realize that what I'm feeling with some of this community has strong similarities to fundamentalist religious methods of conversion. Hrm, interesting.

So, I'll continue learning as I do find the language very interesting, although I haven't really found it to do things in any sort of way other languages cannot with as much or more expressiveness.

Friday, May 16, 2008

Absurd

Some time ago, a company I've recently (1.75 years ago) left was bought by another. This all happened after I left, so it didn't affect me other than it directly affects friends that are still there. One of the acquiring company's MO's is to do an immediate 30%-40% headcount reduction (or so I am told).

True to form, they announced the RIF in the department I was in, and soon after noted who will stay (very few) and who will go (very many) and who will be doing the jobs of the people they let go (outsourced).

The other day, someone realized that the company's business is financial in nature, and it was against [the law, company policy, a regulation] to allow this personal financial data to leave the US borders. The solution? NOT fire the people that were going to do those jobs? Oh, but no! They instead decided to bring ONshore the OFFshore employees to do these jobs, and pay them about the same as the people who already knew how to do it.

Cost savings, indeed.

Discuss.

Wednesday, April 23, 2008

Curious Design Choice

In eclipse, in the java editor, Ctrl-S (save) is RIGHT NEXT to Ctrl-D (delete line).

I understand WHY they are, but it's a bad design all the same. Often, if you're not accurate, or you're using the typical crap laptop keyboard, one can hit both; in the wrong order this can be rather irritating at best, disastrous at worst.

Any other examples of this?

Friday, April 18, 2008

Creative Employment Agreements

I was chatting with a coworker today about some company issues, and I had offhandedly mentioned a thought I've had over the past few years; that being, putting something in your employment contract/offer letter/acceptance/etc. that wasn't already there.

In my case, had I remembered it when I joined this company; this is an old, old thought that I've never followed through on; I would have specified:

  • Any "team building" exercise FOR the sake of team building, I would be free to opt-out of.
  • I am not required to attend weekly status meetings.
  • I am not required to submit weekly status reports. I would of course couch both of these in terms of being perfectly happy to provide relevant status updates to my manager, just not in the "Management 101", Andersen Consulting style TPS reports and meetings.
  • Probably something about meetings. This is a little easier; one can just not accept invitations if it's not convenient, which I often do already.
Naturally the company would be perfectly within their rights to NOT hire me with these riders on the contract and I accept that. It just seems like these types of things would be as much or more easily negotiated than the standard pay or vacation time items.

Has anyone done anything like this? How'd it work out?

Thursday, April 17, 2008

What's A Good Error Message?

What makes a good error message? As developers, we certainly see a lot of them, and they are almost always the first indication that Something Bad (tm) has happened. So what makes a good one?

In order to answer that, it's probably best to illustrate what they are FOR. There are generally 2 classes of error message:
  1. Messages intended for users. These messages indicate that the USER has done something wrong. Typically bad input.
  2. Messages intended for the developers. These are TYPICALLY cries, bleats, or yelps for help to tell the programmer that something unexpected has happened.

Since this isn't "Adventures in Usering", I'll focus mainly on the latter.

So what makes a good error message? I've given this a bit of thought lately, and I think that a really good error message has the following 4 qualities:
  1. It tells what was expected.
  2. It tells what it actually got, and how or why that is different than what was expected.
  3. It tells how or why this might have happened.
  4. It gives some direction on how to fix the problem.

As an example of a good error message, let's look at some pro and counter examples.

The ultimate counter example of all 4 qualities can be seen here

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler

Awesome. It tells me, as a developer, absolutely nothing useful to find out what the heck happened, what was SUPPOSED to happen, where it happened, or what I'm supposed to do about it. This particular nugget occured while starting up an application server. Since it is java code, I was able to see the stack trace that led to it, so I had a very small clue as to where to start looking.

This is an example of a very common type of error message; the "I'm an error message" message. We've all seen these; they provide no useful information other than the fact an error occurred. A message announcing that an error occurred is obviated by the fact the message is there at all. I used to joke in college that I was going to write a compiler and to save message space, it would have one error message that said simply, "No". I didn't think so many developers would steal and stylize my idea, but apparently they have.

So what would have been better?

Tell me what was expected

In this case, this error was the result of a missing file that was needed during some startup code. So, tell me that.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml

NOW we're getting somewhere. Even with THIS bit of info, I might have an idea by putting together that there IS an error message, and that it's saying that it's expecting to read from a given file, that maybe something is wrong with that file. My years of experience might lead me to see if that file exists, its permissions are such that it can be read by the app, it looks "ok" (not zero length, the format matches what it probably should (xml), etc.)

Tell me what actually occurred

Now that we know what the app wanted, an indication of what differed from this expectation would be nice.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file was not found

Hey now, this looks promising. And spares me the checks I would have had to make if this tidbit were missing, as before. Too, it disambiguates from something like...

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file is not readable

Tell me how this happened

Unfortunately, this isn't always possible, and sometimes the first 2 bits of information are more than enough to get started. But when writing error messages, if you have any idea of how the error could have occurred, put it in the message.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file is not readable. This can occur if permissions are set incorrectly on the file or its directory. This happens often during an initial setup of the application, since this file is deployed separately from the application itself.

Be careful here, this might lead a developer or tester to the wrong conclusion. When writing error messages, if there are a litany of reasons an error might occur, I will often leave this step out since it would be too much to list them, and just listing some might cause one to not check the others.

Tell me how to fix it

This one can also be tricky, since it's often not known how to fix the problem, especially when the error message is first being coded. However, I've found that over time developers will tend to see a certain error and know what causes it. If possible, that's the time to go back and fix the message (if possible, and it often isn't). Or of course, sometimes an error can only be fixed in a limited number of ways. So, list them.

Exception data: com.stuff.SystemException: Failed to initialise or configure service: config class com.stuff.ConfigurationImpl, prefix DefaultHandler, serviceClassName com.stuff.DefaultServiceExceptionHandler. Expected to read from file: /opt/apps/config/i18n.xml, but file is not readable. This can occur if permissions are set incorrectly on the file or its directory. This happens often during an initial setup of the application, since this file is deployed separately from the application itself. Check the permissions on /opt/apps/config/i18n.xml to ensure they are readable by the application.



Although I've gone a bit off the deep end on this particular example, if I'd had this information on this very real message (but somewhat obfuscated to protect the perpetrators of such heinousosity), it would have saved a lot of debugging time. In this particular case, the application reads a file that lists what OTHER files it should read, and it was one of those second level files that was missing. Because the error message was so vague, I had to step-debug into the code at that point, and check EACH LOOP ITERATION until I found the offending iteration and fix the file it couldn't find. This took the better part of a half hour, and it wasn't the first time, so I knew where to start. Two minutes by the original programmer would have saved me and coworkers of mine hours of debugging time.