Coming from Siemens or Modicon, the first shock of Logix is what's missing: there are no %I0.0 addresses anywhere. Every value is a named tag with a data type. The one question to settle for each tag is its scope: is it controller-wide, or private to one program? Get scope right and your programs never step on each other.
Two programs, Infeed and Palletizer, each have their own tags, and there is a controller-scoped pool that every program shares. Switch the view to a program and watch which tags it can actually reach: its own program-scoped tags and every controller tag, but never the other program's private tags. That's why both can safely own a tag called Step.
Switch to Palletizer and notice its Step is a different tag from Infeed's Step: they share a name but sit in separate memory, so they never conflict. Controller tags (LineSpeed, EStop_OK, all I/O) stay visible to both. You get encapsulation without using a single address.
A tag's data type decides what it holds. Beyond the atomics, Logix has predefined structures (a TIMER is a tag with .ACC, .PRE, .DN members) and you build your own with UDTs.
An alias tag is Logix's nod to readability: StartPB can alias Local:1:I.Data.0 so your rungs read in plain English while still pointing at real I/O. The whole program is built on the tag database, not on an address map.
Two programs each declare a program-scoped tag named Step. Is that a problem?