Jump to content

David Schwartz

Members
  • Content Count

    1190
  • Joined

  • Last visited

  • Days Won

    24

Everything posted by David Schwartz

  1. https://en.wikipedia.org/wiki/Value_semantics#:~:text=In computer science%2C having value,implies immutability of the object.
  2. David Schwartz

    general question about embedding docs in an app

    This sounds exactly what I'm looking for. I'm curious what you use for that "local table" that you mention, and how you "update in the exe". Does this extract something to a table when the program runs, and always use the extracted version? (Kind of like embedding a .hlp/.chm file into the EXE) Or does it run from some resource in the EXE unless it's going to be edited, then do something like a "copy on write" to allow it to be edited?
  3. David Schwartz

    general question about embedding docs in an app

    Well, I would like WYSIWYG in this case.
  4. David Schwartz

    general question about embedding docs in an app

    Displaying content is not the issue, which is why I said I'm not looking for something like HTML Components. TMemos show normal text; TRichEdits show fancier markups; and TWebBrowser shows HTML. The point is not DISPLAYING but being able to EDIT, SAVE, and VIEW from within the app. The options to SAVE the data are: 1) edit the components in the IDE (TMemo, TRichEdit) 2) hard-code the text in the code 3) maintain a separate file -- easy for text, modest for RTF, more complicated for HTML and help files The data can go into a DB (eg,. sqllite) or just some other kind of file.
  5. There are TONS of places throughout the VCL where the original developers could be accused of not thinking through the various use-cases enough to have a clear idea of what methods should have been tagged as protected rather than private. I think they tended to err on the side of keeping things private that didn't have obvious reasons to override them at the time. I see plenty of libs where the devs went the other way and stuffed nearly everything into the protected section instead of private, leaving a huge invitation to hack the crap out of things. I've often run into this situation in my own code, where I needed to override a method in a child class but I left it as private in the parent/base class instead of protected. It just didn't occur to me that I'd ever want to use it in a child class. Honestly, this is an area that you could spend a ton of time sweating over prior to a product release, and if you're in a hurry like most projects, it just never gets addressed. And that's why there are hacks for that ...
  6. Here at work we're advised to do a 'git pull' frequently throughout the day, and especially before and after switching branches. I guess this is because we've got a lot of quick-turn work rather than long-term dev work. Does anybody else do that?
  7. David Schwartz

    git workflow question

    Well, let me try asking this here and see if anybody has any suggestions. It's about our workflow. It's probably more info than is needed, but it gives a broad overview of what we're dealing with. I know that git itself is neutral as far as workflows go. Someone published a guide called "gitflow" that is designed for a workflow followed by typical software development organizations. That fits for the last few places I've worked, but it does not fit the organization I'm currently with at all, nor any of the similar models targeting that kind of environment. Unlike gitflow, we do not have a team of people working on a core set of code that evolves over months and months. We have a few people, sometimes just one person, working on a constant stream of very small, independent quick-turnaround requests that get updated and pushed into production in a matter of hours or days. THE BUSINESS MODEL If you're interested, here's the business model: This is a business that started out to do high-volume printing of bills, statements, and invoices, and got pulled in a different direction by every client they got. On the surface, it's a simple mail-merge process. In practice, it's a nightmare. Every client submits data to us in a different format. Most of our "clients" are resellers, like a property management company that manages apartment complexes, or condos, or rental properties. Apartments here send out two or three things a month: an invoice for rent, a statement for water and maybe trash, and some send out a newsletter. The management company uses the same templates for all of the properties they manage, but they'll each have different names, logos and return / remit addresses. So they send us a file with account data and whatnot and we have to consolidate that into a page-by-page printable stream that's sent to what amounts to a huge laser printer. It starts with a 5' roll of 18" wide paper at one end, and spits out USPS trays of sealed envelopes (pre-sorted by zip code) that contain folded materials with whatever else is needed, often with inserts like return envelopes and other kinds of coupons. The same thing everybody gets from their utility companies, gas company, water folks, department stores, etc. No two are alike. That's what the business DOES. THE WORK As far as the work goes, it's a little hard to describe. They SAY it's "programming" but I don't really know what to call it. It's mostly clerical work IMO. Aside from new account setups, eg, a property mgt company brings on a new client of theirs, most of our work consists of changing logos, return / remit addresses, and verbiage on statements -- like "here's what we want in the message box for September's statements: _____" kind of stuff. Back around 2004, a team built this rather convoluted framework in Delphi that handles every aspect of this business. It has been running very nicely since then. An investment company came along in 2012 or so and bought the existing company and most of the developers left. Nothing much has changed since then. The core of all our work is the data import process. As I said, every one of our clients use a different format, although the data for individual accounts from the same client / management company is pretty much the same since it all comes from the same management company. The import process for each account is handled by a Delphi app that runs by an automation process. One of these lives in a folder designated for either a single account (eg., property) or group of accounts managed by the same client. We get requests almost every month to tweak the bills. In a perfect world, we'd bring up a WYSIWYG tool that looks like Word, make a few changes, and save it. We're far from that. Changes to data displayed on printed materials can occur in a half-dozen different places, some static, some dynamic, some in-between. Input files are in a variety of formats: XLS, TXT, PDFs (that we scrape or use OCR to read), and lots of indescribable proprietary formats. The import apps are in Delphi. The intermediate files are mostly PDFs. The page markup language is TeX. When we get a request in, our first task is to figure out which file or files needs to be modified. We make the changes, do some testing, then finally create a "proof" (a PDF file) with some test data from the client to show them the results. When they say it's OK, then we "push it into production". From start to finish, it can take 10 minutes to several hours to do the work needed to process a single change request. Frequently this work spans several days due to questions or issues that come up. Once work is done and we send a proof out, it can take hours to days to get approval back. We don't push anything into production until we get approval. We use git to track all of the changes in our files. Our work is focused on "tickets" where we need to make the changes requested in a given ticket. So we set up a branch in git to capture file changes for each ticket. We can alternate work on different tickets throughout the day. We can put work on a given ticket "on hold" for a day or more. It's rare that we can work on a ticket and get it approved by a client and pushed into production the same day, but it happens. It's usually the approval process that causes the greatest delays. Larger clients will submit tickets for several different accounts the same day, and they can be handled by different people in parallel. Their data is all in the same folder, so we're all working with different data, but sometimes it's in common files. Many clients keep a list of accounts in a single CSV file, for example, that our software reads to get static data for a given account number. This acts as a very simple database. Obviously, it needs to be updated in Excel or a special editing tool someone made for us to use. Some of these files eg., common CSV files, some template files, etc.) are pushed into production b/c they're read at run-time. Actual "source code" files are either compiled or generated on-the-fly so are not pushed into production. Either way, they need to be captured by git. Everybody works on a local copy of the data that resides on our own computer. We rely on git to handle merges and merge conflicts. The problem is that from time to time, get gets confused. We recently found something pushed into production where the file that was changed had been reverted to the previous version of the file. Somehow git messed things up. Git showed the previous version as "current" and it replaced the modified version that was actually newer. In another case, a guy went through a common client file and commented out about 1/3 of the lines in the file, saved it, and pushed it into git. Two weeks later, we discovered everybody had the unedited version on our local stores that git decided was "current" and we were changing and pushing into the repo. We don't know how that happened, but it caused problems. In summary, we have lots of quick-turnaround work that's done for individual accounts. Some common files can be changed by the same or different people actively working on different tickets. We can also have multiple tickets in the same folder that we work on the same day that are for different accounts but touch one or two of the same common files, so we need to switch branches between tickets to ensure we only capture changes made for individual tickets. I should also mention that we have a couple of folder trees mapped to local drives that we use to isolate things for git purposes. All of the folders in which we keep files for client accounts are contained in the I: drive. It has a .git file in its root so everything we do applies to the whole drive / folder tree. This is quite annoying at times b/c a lot of files show up as changed that we never touched, are not interested in for a given ticket, and are often forced to deal with for conflicts before we can work on our tickets that are totally unrelated. It would be really great if we could get git to let us focus only on a specific folder and ignore everything else on the drive. I don't mind conflicts, but let me deal with them when I'm working on a ticket related to those files, not something totally unrelated.
  8. David Schwartz

    string helpers question

    I'm using Tokyo 10.2.3 and poking around the string helper functions, and noticed there's a function .Contains( string ) : boolean I want a case-insensitive version. ContainsText(string) doesn't make sense. But then I noticed there's a Lowercase function. But it's Lowercase(string).... These are all class functions so they don't have an object/record attached. So given var aStr : string; it looks like you can't say: if aStr.Lowercase.Contains( 'xyz' ) then ... You need to say: if ContainsText( aStr, 'xyz' ) to get what you want. So what's the point? Looking at the members of this string record helper, it appears that a ton of members are functions that take an argument that should be the string they're "helping". I'm kind of baffled at the apparent lack of utility of: aStr.Lowercase(aStr) when it's the same as Lowercase(aStr). There's a nice variety of functions there, but since they all take an explicit argument, they appear to be gratuitous since the string in front is ignored. What am I missing?
  9. David Schwartz

    string helpers question

    My question had more to do with the fact that the string helpers all appear to take an argument that's redundant. that is, (aStr.LowerCase = LowerCase(aStr) should be true. Here you apparently need to say: aStr.LowerCase(aStr) which just seems silly. There are a TON of string helper methods that require the parameter you're working with as an explicit argument.
  10. David Schwartz

    GLAD loader for Delphi

    There's an underlying assumption in most communications that requires you know your audience. People who do not fall into that assumed group won't follow what you're saying. It's like listening to a bunch of "inside jokes". How fun is that when you're not privy to what's happening "inside"? If this were a PRIVATE library and this were a PRIVATE discussion between two people, that's fine. In that case, 100% of the participants know the background context. The "open source" part is irrelevant. The fact is, it's taking place in a PUBLIC LIBRARY. There can be hundreds of people looking at it from all around the world, at different times and with completely different backgrounds and perspectives. Adding a simple line at the top that answers the question "What is this about?" and maybe a link (as was offered above, independently of the content in the library) so people at least know what to look for would really be sufficient. As a participant, if you think it's a private discussion, you're going to think it's implied, so why bother stating the obvious? But everything in github is PUBLIC! In general, that's not a valid assumption for over 99% of the people who might view it other than the one or two others you're communicating with. Making a practice of adding a one-line description that answers the most obvious question everybody new to the page will have, "What is this about?", with maybe a link for more info, hardly requires a doctoral thesis. What it DOES ENABLE is MORE INCLUSION AND PARTICIPATION BY OTHERS, which is supposedly the whole goal of the Open Source movement. You don't need to write a damn book! It's a simple one-line description that answers the question, "What is this about?" and a link to learn more. Otherwise, you're simply having a private conversation in a public forum that very few other people are able to follow. And just to be clear, I'm not saying there's anything wrong with that! But the OP posted a message here ANNOUNCING this open-source project and when I went to look, the first question I had -- "What is this about?" -- was not addressed anywhere! All I saw was bits of a private conversation between two people who knew exactly what each other was talking about, and everybody else was relegated to evesdropping. The popular retort is, "Well Google is your friend!" Hey, this is YOUR announcement! Why do you then say to ask Google if I want more information? Why did you bother to make the announcement in the first place? It's like getting in front of a group of several hundred people and announcing, "Hey, we're having a party!" and someone asks "When?" and you say, "ask Google!" and you walk away. I don't know about you, but I'm not wasting another second thinking about it. And I'm not asking Google because adding the Who, Where, and When part is too much trouble for you to mention after the What. I'm guessing the OP posted that here because he wants people to look at the work, maybe see some value in it, perhaps get involved. But if it cannot answer the basic question, "What is this about?" then what's the point of making the announcement? Ask Google? Really? Why bother making the announcement? No, if you CHOOSE to make a public announcement about something, you owe it to your visitors to have at least one line at the beginning that answers the most obvious question every single one of them is going to have: WHAT IS THIS ABOUT? How much time do you expect others to spend trying to answer that most fundamental question before they just turn and walk away? This is a basic building block of how you include others in conversations or not. It happens at parties and social gatherings all the time -- you wander around, listening in on conversations here and there, to see if there's something interesting to follow or jump in on. If you're like most people, you wander around sampling lots of different conversations, and don't spend much time if you cannot get your bearings on what they're discussing. It's no different in public forums online.
  11. David Schwartz

    git workflow question

    Thanks for this. I'm not clear how on 7, "git reset --hard" clears changes from the working directory. Don't git commands affect the entire repo? (Our repo includes the entire virtual drive, ~850 folders.) What git GUI tool do you prefer? We only have free stuff available, but I did use Tower for a while a couple of years ago. I have the right-click Git GUI option, along with Tortise git. --------- In a more abstract sense, I think what they're trying to accomplish here is to use git for two purposes. One is obviously to keep a version history of our work. They say that if something in Production turns out to be trashed, we need to be able to roll-back to the previous version. What's happening right now (using that sequence I showed above) is that git is reverting things right before we push the files into production, and our changes are lost. Rolling-back doesn't help -- our changes are not in Master. However, I discovered they're still in the local branch, as long as I haven't deleted it. I think it's b/c of something wrong we're doing above. The other purpose is to use git to distribute changes to everybody's local machines so we're all in sync with all of the latest updates. The theory being if one of us gets hit by a proverbial truck (or we catch COVID), someone can come in and start working where they left off because they've got all of the latest files (well, those that were committed and pushed properly, anyway). This has two negative consequences that I've seen. One is that two different people working in the same folder at different times can cause conflicts to arise fore everybody else who never touched anything in those folders. This is a time-related artifact that only happens if you do a pull in the time interval when the conflict arose and was resolved. If you have a team of 50 people and a conflict arises between two of them, I don't see why the other 48 are forced to even see it let alone deal with it on their machines. This is supposedly a "feature" of git. (Maybe this is also a reflection of how we keep pushing stuff to Master instead of maintaining a dev branch. We do quick turnaround stuff on isolated tasks, so dev branches are meaningless.) The second is the complexity added when we're modifying the same files for different tickets that are for independent needs but happen to address data in the same files (and folder). I personally think it would be a whole lot easier to use something like Dropbox for this latter purpose. sorry if I'm sounding redundant, but I hate having to spend my weekends cleaning up messes caused during the week b/c nobody at work seems to know what the problem is (or believe one even exists).
  12. David Schwartz

    GLAD loader for Delphi

    So why isn't this stated in the README somewhere? That's my whole point.
  13. David Schwartz

    RzLauncher vs. Win API call

    I'm using the TRzLauncher (part of the old Raize Library available in GetIt from Konopka) to launch some apps from another app. For some reason, it will sometimes just stop working. It does not generate any sort of error, it simply doesn't do anything. I've had no problem running the same things using windows API calls, or going into the File Explorer and using right-click -> Open With... It usually works again if I close something else that I'd opened first. It also works if I close and restart the app itself. So I'm curious if there could be some odd memory limitations using it that don't apply if I'm calling the Win API directly. FYI: I drop one of these on the form and re-use it in a bunch of places in order to avoid having to manage individual instances of it. As I'm typing this, I'm wondering if there could be a reentrancy problem with it? This only happens if I launch something and say to not wait for it to complete. Then it won't let me launch anything else. I guess the Win API doesn't care, but the component might. The help doesn't mention this anywhere. It's a really simple component, but I guess that could be an issue. Any thoughts?
  14. David Schwartz

    RzLauncher vs. Win API call

    Thanks. I looked at the code, and the name CDir did not stand out to me as what I was looking for.
  15. David Schwartz

    git workflow question

    I posted this earlier, and I'm convinced there's a problem with it. We went through and made a bunch of changes to a few files yesterday while in a specific branch. Then we used this process to effectively "check-in" the code -- ie., sync it with master. Today I went in and started to do some work where I left off, and got a bunch of errors. I was working in master, and started looking at the code, and none of yesterday's work was there! I freaked out, because the files pushed into production were from master, and they're wrong. So I started making the changes again, and then realized I was still in master. So I tried to checkout the previous branch and got an error warning that it would overwrite the two files I'd been trying to update again. I just renamed them and ran the checkout again, and it worked. I examined the files and ... lo and behold ... there were my changes! WTF??? What's wrong with this process? (NOTE: I did not come up with it, a colleague I work with did, and he swears by it. I swear AT it. There something wrong with it!)
  16. David Schwartz

    GLAD loader for Delphi

    Like so many projects people post on github these days, the README seems to cover everything EXCEPT: "What IS glad?" People are just supposed to know this stuff, or search around the internet to find out. Or, you don't care if anybody who doesn't already know what it is learns about it from your post -- IOW, you're basically just "preaching to a choir" and everybody else can just mosey along. Sorry, I'm just exhausted dealing with lack of comments and descriptions of stuff the previous people who maintained the code apparently just kept in their heads. When I ask for help or explanations, I'm told, "Just fire up the debugger and step through the code..."
  17. David Schwartz

    is the site infected?

    I fatfingered something over the weekend and a page came up with a bunch of naked men on it. Not my thing. But ever since then I've been getting weird stuff happening here. I'l click on a link and the form will open in another tab while the previous one opens some spammy site. One that keeps showing up is digitaltrends-dot-com, but it's not the only one.
  18. David Schwartz

    is the site infected?

    I'm switching to Opera on my work laptop here. I don't think IT cares. I like how it can run a few extensions I use in Chrome that I really love. * RoboForm * Session Buddy * The Great Suspender
  19. David Schwartz

    is the site infected?

    It was happening at first only from this site, but it started happening in other browser windows, so it's probably not related. Our IT Dept puts so much crap on our machines for both security and general protection it's hard to believe. The CPU activity is constantly jumping around when I'm not doing anything. I don't like it. Anyway, all that "protection" and something apparently snuck through. <sigh>
  20. David Schwartz

    RzLauncher vs. Win API call

    For the situations where I need to launch and not wait for return, I create an instance dynamically and did some contortions so the OnFinished event handler kills the instance. But when you open a file in, say, Notepad++, it's really irrelevant. If you close the program before these instances have closed, they get freed anyway. The Windows API doesn't seem to care, so I could probably just launch them and forget them. As an aside, I was also looking for some code to launch a command and get the STDOUT back. Someone pointed out that JVCL has something built-in, an Execute function. There are actually several variations. But I couldn't find one that lets me set the working directory, which seems rather odd for such a complicated bunch of code. I found something else here that takes a working dir param, https://delphidabbler.github.io/delphi-tips/tips/61.html but it doesn't capture STDERR. Seems to always be something missing. 🙂
  21. David Schwartz

    best way to display a list of panels?

    That is something I want to do. In fact, I added right-click menu options for "Move up ^^^" and "Move down vvv". It's simple to move them on the list and then refresh the display. A drag-n-drop approach would be nice, but it's not worth the trouble for what I need.
  22. David Schwartz

    RzLauncher vs. Win API call

    since you're familiar with it, maybe you can tell me if it would suffer from the same problem?
  23. David Schwartz

    How to handle generic hyperlinks in TRichEdit

    I posted this in SO and it was closed with a ink to another post. @FPiette offered to share some code he had done previously that does it. I thought this might be a better place for that.
  24. David Schwartz

    git workflow question

    I didn't come up with this. The guy who made it added the "... resolve conflicts" bit because we keep getting conflicts arising in stuff we're not working on. Our boss has even experienced that and he can't even explain it. Our so-called "git experts" said, "Well, you shouldn't be getting any conflicts". That's nice to know, but we are. At one point I _did_ stash some changes, then 5 minutes later I tried to pop them and got an error saying there were conflicts. I do not understand this stuff very well, obviously. I'm being told to "follow the scripts" and we get problems. Then I'm told the same thing you're saying, "Well obviously you DID mess something up and so you need to FIX it!" No, all I did was edit some files in the one folder that was associated with what the ticket I was working on related to. I did not touch anything else. And again, when I say that last bit, everybody hears "he's being defensive and trying to blame someone else!" I'm just trying to get ahead of this a little bit. I'm fed up with all this crap happening in other folders that I'm not visiting, and people suggesting that it's something I did. They don't want to listen to my explanations. From my standpoint, I just want to get rid of all these other folders and just focus on the few I need to do m work. But that will cause other problems. 🙂
  25. I'm looking for design ideas in terms of how to approach this process model from a UI perspective. This isn't something that gets discussed very much here, so I thought it would be fun to see what others have to say. FWIW, this is something I'm building to save my own sanity at work. 🙂 Say you have a process that has several steps, eg: o Prepared o On-boarded o In Progress o On hold / problem / issue o Waiting for more info o Pending signoff o Completed I set these up using a TRadioGroup. It works ok, but I'm finding things "falling between the cracks". So I'd like to break each one into more detailed steps. If there are sub-steps, each of the sub-steps must be checked-off in order to get the entire step marked as complete. Some can be optional, but the required ones need to be checked or some alert will be displayed. The nature of things is you can't really jump ahead, but you can go back -- mainly to the hold or waiting steps then back to "In Progress" "Pending signoff" might breakdown into these sub-steps: -- Team code review (optional) -- Team signoff -- Publish to QA server -- QA tests complete -- QA signoff FWIW, this is not intended to implement a fancy and highly-controlled workflow of any kind. Rather, it's intended to be more of a GUIDE ... a list of things to remind us of all the detailed things that need to be done for different kinds of tasks, like a checklist. There's a similar approach to each task, but they have some variations depending on different things, and it's often hard for us to keep the differences straight. So having a list that's customized for a related set of tasks (or task group) will help us keep from doing stuff that's not needed, or forgetting things that are needed, for each kind of task. For example, one group of tasks might require you to paint things green, while another might require them to be painted white. They all require being painted, but having a specific thing that says what color for a given group is often very helpful, so you don't have to ask someone or go searching through your notes. It's not obvious if you don't know, and not well documented otherwise. Until you've done it a few times, that bit of missing data can slow you down quite a bit. So rather than simply saying, "Apply paint" the step would say "Apply GREEN paint" or "Apply WHITE paint" or whatever, depending on which task group it belongs to. That's what I'm trying to get at here. For any given group of related tasks, their lists would be pretty much static -- that is, the steps involved change very rarely. (They've been in place for years. The problem is, one guy has been doing them for years, and he has forgotten more than he can recall. In training us to do this stuff, he's missing lots of little details, and we're having a hard time documenting this in a way that makes it obvious at the time we need to know.) Timing wise, a lot of these tasks can be handled in an hour or two, most within a single workday. Sometimes they end up spanning several days, especially when they get put on hold while we wait for clarification of ambiguous or missing details. This would also make it easier to bring on new people. How might you approach this from a UI design standpoint? (I don't expect to see a single component that does it all, but who knows?) (I'm not looking for how to store this data in records or lists ... but how to represent it visually on the screen using VCL components.)
×