Archive for category Uncategorized
Our scanner at home is an old flatbed that scans to a .jpg file. When you have several pages that you need to scan and send to someone, a pile of JPGs isn’t very nice—you’d rather have one PDF.
If you’re running Linux (at home I’m currently running Fedora 20 – “Heisenbug”), this is easy peasy: with ImageMagick installed, just use the
convert 1.jpg 2.jpg 3.jpg 1-2-3.pdf
FT # A label (for jumping to) NEW X,MSG2 I $$RDVALS^MISC22()=SUCCESS DO QUIT # The second space between DO and QUIT is significant . S X="DO ACTN5^ACTNS" . X X # The two Xs mean different things (Cache' is not a context-free language) . S MSG2=MSG_" succeeded." # Expect MSG to float in from somewhere else E DO . S ERRMSG=INVALIDREADMSG . W 1/0
STDMETHODIMP CI3DBTranDataSet::GetReal(), man.
Today, while looking for the Reasons article about which I just posted, I found out that Jerry Weinberg has recently come out of what was supposed to be terminal cancer. I was moved to write him this letter, which I sent this morning:
June 3, 2010
c/o Dorset House Publishing Co.
3143 Broadway, Suite 2B
New York, New York 10027 USA
Dear Mr. Weinberg,
As a computer programmer of thirteen years, I have read and benefited from your writing – specifically, Exploring Requirements and Are Your Lights On? Thank you for working to understand what’s wrong with how the people within software development organizations think and articulating what needs to change and how. Your work has made a difference to me.
I went to your website this morning and saw that you have had a battle with cancer. Recently you were declared cancer-free — praise God for that!
Mr. Weinberg, you have had a brush with death, and because I love you I need to warn you of the Day of Judgment that we all will face. On that day, what will you say to the King?
I do not know the state of your soul before God, but I implore you, please do not deny the existence of the King. God who made the heavens and the earth and gave you every breath you’ve ever taken rules in righteouness, and he will call you to account one day. All have sinned and fall short of the glory of God. Only those who repent and believe in Jesus Christ will be saved.
Oh Mr. Weinberg, repent and be saved!
Sincerely and with love,
Daniel S. Meyer
I don’t have a mailing address for Mr. Weinberg, and I don’t know if his publisher will forward it on to him. Even if they do, how likely is Mr. Weinberg to repent? Am I not a fool for doing such a thing — not to mention for advertising it here? Where is my respectability?
Brothers who are in Christ: souls are at stake. Fool or no, I care about Mr. Weinberg’s soul. On Judgment Day I want to be able to look in the eyes of all, knowing I was faithful to warn. And may God grant repentance to those He has chosen!
As developers, we consider ourselves to be logical thinkers. And to an extent, we are able to think logically, to find and implement technical solutions.
But is our decisionmaking driven by cool reason? Yes, we say — by cool reason.
What about when we communicate our evaluation of a Microsoft tool to co-workers? Cool reason?
The fact is, many of the decisions we make as developers are made based on emotional arguments couched in technical terminology. Reading a post by Jerry Weinberg several months back brought on an Aha! moment that changed my thinking about us developers.
From Mr. Weinberg’s post titled Reasons, then:
Recently, I found myself recalling that summer day, half-a-century ago, when a client asked me to find out why their Software Engineering Process Group was having so much trouble getting people to adopt new software tools. It couldn’t be the tools themselves, they reasoned, because quite a few people had adopted them and liked them. So, I set out to interview both adopters and rejecters, to discover the reasons some were using the tools and some were not. Here are some of the answers I obtained:
Darlene: I installed it because the boss told me to use it.
Porter: The boss told me to use it, so I didn’t use it.
Ursula: I installed it because the boss forced me to use it.
Marcy: The boss forced me to use it, so I installed it, but I don’t use it. He wouldn’t know the difference.
Quentin: I used it because it was like what I used before, so I knew I wouldn’t have any trouble adapting to it.
Chuck: Why should I use it? It’s nothing new; it’s just like what I used before.
Carl: Hey, I used it right away, because it was new and different.
Cynthia: I’m not going to use anything that’s new and different. Too many things aren’t tested, and something’s sure to go wrong.
Mary: Of course I used it. Everyone else was using it.
Roy: Everyone else was using it – what a bore! You won’t catch me following the crowd.
Frances: Why should I use it? Nobody else was.
Edgar: Hey, I got to be the first one to use it!
Mort: I couldn’t use it. It didn’t do all the things I needed.
Alan: The thing I liked best about this tool was that it didn’t try to be a Swiss army knife and do everything anyone could possibly want.
Gerri: It was the perfect tool, because it had every feature I could possibly want.
Chico: Every time I hit a key by accident, it would invoke some obscure feature that I didn’t want in there in the first place. Finally, I trashed the whole thing.
Orion: I’m so busy, I needed a new tool to save me some time.
Belle: I’m so busy, I don’t have time to install and learn a new tool.
May: I’m not that heavily loaded. Why would I need a time-saving tool?
Paul: Well, I wasn’t so busy with other things, so I had time to install and learn a new tool.
Earl: It was freeware, so it was a bargain.
Justine: It was shareware, so it couldn’t have been any good.
Jacob: This tool costs $3,000. It must be good, so I’m using it.
Neelie: I’m saving the company $3,000 by not using it.
Willis: I won’t use it because I don’t like the way Microsoft makes software.
Samuel: I knew it would be good because Microsoft makes it.
Well, there were more, many more, but that’s enough of the infinite reasons to make my point. By this time, you may have noticed that I have arranged these reasons in pairs. Why? So you could see the pattern that I saw:
Every single reason to use the tool was matched by the same reason for not using it – and vice versa!
In other words, these reasons may look like logic, but they’re not logic – they’re just reasons. In logic, the reasoning comes first, then comes the decision. But in real life, it’s usually the other way around – first we make the decision, then we make up whatever reasons we need to “justify” the decision and make it look like logic…
Going back to the Microsoft example again, when the Microsoft tool blows up, do we have cursings at the ready? If so, would we have had similar cursings at the ready if it had been our favorite open source tool that blew up? If not, why not? Are we of a mind to be understanding toward our open source tool and impatient with our Microsoft tool? (The question has the same implications if we reverse the inclinations — positing a tendency for patience toward the Microsoft tool and impatience toward the open source tool.)
What I have described is not a logical argument about a tool. It is an emotional argument about a company. Perhaps there is an argument to be made against the company (“Where possible I do not support Microsoft because of its history of corrupt business practices regarding smaller innovators in the market” would be an example of a moral argument.) Cloaking such a moral argument as a technical argument against a particular tool, however, is not honest. As developers, we don’t even realize we’re doing this, but we need to realize it. It’s part of being a professional.
Read Weinberg’s whole article.
We programmers are a proud lot, aren’t we?
We can do things our family members and friends can’t do. We can take lifeless bits, wave our hands, and make the code live! We have logic. We have design and problem solving skills. We have honed our technical prowess.
All this is good — but there is a problem: We imagine that we live in a larger world than the non-technical people around us. Brothers, let us not be deceived: our world is a smaller world.
What do I mean?
Our technical expertise does not help us prolong the life of our sick child — we thank God for the doctors and pray for grace.
Our design skills do not give us boldness to warn those who do not love Jesus of the judgment they face if they do not repent.
Our logic does not teach us how to live with our wives as with a weaker vessel, leading with honor, gentleness, and strength.
Our ability to do what others can’t do does not confer on us a special ability to honor our father and our mother as we know we ought.
These are matters of eternal import where we are no better than anyone else — and often worse!
Brothers, in our daily work we’re living in a virtual machine.
Yes, let’s continue to work to solve problems, to help people with our software, to work as unto the Lord — but let’s never forget that the rules are simpler inside this machine. The hard problems are out there. We don’t know how to solve those problems. Sometimes we don’t even try to deal with those problems — we hide inside our virtual machine, where the universe is smaller and the rules are better defined.
It’s not wrong for us to do our technical work. But we should be the humble ones, not the proud ones. Brothers, let us remember this.
I have thought for some time that it would be fun to learn fencing. Today I found out what can make fencing a VM so helpful.
A bit of background: We have a VMWare virtual machine farm. Someone sets up a VM with one of the nightly builds, and then developers or testers can clone those VMs for their own testing. Nice! The one snag is the IP address – if you simply clone the machine, the address will conflict with every other clone on the network. There are two ways around this.
The unfenced route:
- Discard the state of the config
- Open the config and go to Properties of the VM
- Delete the NIC and add a new one
This has the disadvantage, though, of you having to discard the state of the machine first (having the effect of setting it back to a power-off state? something like that?) All other things being equal, this would not be a big hardship, but when we’re testing on nightly builds, the system can be a bit fragile (ok, really fragile) and there can be issues restarting all our subsystems and getting them into a happy enough state to test. Whoever it is that sets up the VMs from the nightly builds gets the subsystems running and that’s the state in which they save the VM. I was losing that work when I discarded state to go the unfenced route. Then I had to spend time getting the subsystems running myself. Waste o time!
Instead, when you deploy the VM you can just check the Fenced box, and then the server farm somehow does address translation, finding an IP address unused by any of the other clones. Thus you don’t have to go to the minor work of deleting and re-adding the NIC, and more importantly (for us anyway) you also don’t have to discard the state and redo someone else’s work getting the system into a stable state for testing. Nice!
My beloved three-speed bicycle had three problems, one after the other.
First, the rear tire went flat.
After I fixed that, the chain would skip gears (or at least it felt that way).
After I fixed that, something was slipping, such that when I pedaled hard, some of the effort was lost to just making the rear gear spin. This made for mushy pedaling.
I can hear the clamoring begin to rise: “Throw the old thing away already! Get a new one!”
Now, now… this is my legacy system and it meets my requirements. :) I just want to write down what I did for the latter two fixes, since I think I’ve experienced these same issues in the past and forgot:
Skipping Gears Fix
Why was the chain skipping gears? I never could see it happening, but I do know that increasing the tension of the chain (by loosening the rear axle and moving it backward) fixed that issue.
Mushy Pedaling Fix
Why was the pedaling mushy? When I fixed the slipping gears problem, I moved the serrated washers (these might give the idea) on the rear axle from the inner side of the metal frame to the outer side. I don’t remember why I did this, but it seems to have enabled the mushy slippage. I moved the serrated washers back to the inner side of the frame (working to maintain chain tension!) and the mushiness evaporated.
No unit tests… a lot of moving parts… you start to get scared to change anything… hmm!
As I get up to speed on new technologies, some things have taken some figuring out. I’m interested not only in the conclusions — what worked — but also in the process by which a conclusion is arrived at. By recording my process as well as the conclusion eventually reached, I hope to be able to look back from the end, see where I took wrong turns, and draw lessons from my mistakes. I hope to thus improve my research process so that I can arrive at conclusions more efficiently in the future. (I even have some posts on this meta-topic under the experience tag.)
So I present these series in their goriness — dead ends, rabbit trails and all. Perhaps they’ll be useful to someone else as well!
- Trying Out XA
- XA, JNDI, and Bitronix
- Envers, Spring, and JTA
- Hibernate + Envers + JTA: One-To-Many Problems
1. Trying Out XA
- Trying out XA: untested theory
- Trying out XA, part 2: transaction manager and JNDIView
- Trying out XA, part 3: dead ends
- Trying out XA, part 4: more dead ends
- Trying out XA, part 5: a resource adapter rabbit trail
- Trying out XA, part 6: jndi.properties rabbit trail
- Something works!
- XA transactions: how ’bout them rollbacks?
- Captain, we’re experiencing a configuration problem…
- Join point matching
- Simple JMS transaction rollbacks work…
- Pardon me sir, was that an XA transaction that just rolled by?
- Getting the Oracle XA datasource in place
- The beans, the beans, the Hibernate beans…
- Deploying with Hibernate too
- Finding a JTA UserTransaction
- The process of lamination
- XA: The conclusion of the example
- Testing XA rollback…or not
2. XA, JNDI, and Bitronix
(Testing Outside of the Application Server)
- JNDI without an app server? part 1
- JNDI without an app server? part 2
- Plurals and intuition
- Getting a little quicker with Maven
- XA, JNDI and Bitronix, part 1
- Why the slf4j-jdk14 artifact was optional
- XA, JNDI and Bitronix, part 2: JDBC
- XA, JNDI and Bitronix, part 3: first send
- XA, JNDI and Bitronix, part 4: dancing on the happy path
- A minor simplification: the JtaTransactionManager bean
- Why we wanted a JNDI server for integration testing
- On the classpath
- HSQLDB Says ‘No’; Bitronix Chafes
- java: Dropping the prefix
- Why it wasn’t blowing up when it should have been
- Oracle Treajure hunt
- The Spring problem that wasn’t
- What is an honest MessageListener to do?
- Too many rollbacks
- CS848 – Heuristics of Enough
- Spring and local JMS transactions
- The mysterious mirrored message queue
- JCA Resource Adapters: outbound vs. inbound
- The jms:listener element: hardcoded queue name
- Why there were two consumers listening
- Figuring out MagicDraw, part 1: the mysterious disappearing method
- MagicDraw teamwork projects: Lock ‘n’ Load
- MagicDraw: Run it on your primary monitor
- MagicDraw: Template Bindings
5. Envers, Spring, and JTA
- The versioning isn’t happening, part 1: wanderings
- The versioning isn’t happening, part 2: beforeCompletion
- The versioning isn’t happening, part 3: it’s in UserTransaction?
- The versioning isn’t happening, part 4: Registering with the wrong transaction?
- The versioning isn’t happening, part 4a: phone a friend
- beforeCompletion, I need to figure this out
- An answer
- The final answer
- Blowing up in test mode
6. Hibernate + Envers + JTA: One-To-Many Problems
- Versioning sets: IllegalArgumentException
- object is not an instance of declaring class
- Why envers was blowing up
- Hibernate One-to-Many Foray